Merge remote-tracking branch 'origin/master' into better_object
diff --git a/cpp/poppler-document.cpp b/cpp/poppler-document.cpp
index 998a836..e63d45a 100644
--- a/cpp/poppler-document.cpp
+++ b/cpp/poppler-document.cpp
@@ -86,10 +86,8 @@
     , raw_doc_data_length(0)
     , is_locked(false)
 {
-    Object obj;
-    obj.initNull();
     file_data->swap(doc_data);
-    MemStream *memstr = new MemStream(&doc_data[0], 0, doc_data.size(), &obj);
+    MemStream *memstr = new MemStream(&doc_data[0], 0, doc_data.size(), Object(objNull));
     GooString goo_owner_password(owner_password.c_str());
     GooString goo_user_password(user_password.c_str());
     doc = new PDFDoc(memstr, &goo_owner_password, &goo_user_password);
@@ -104,9 +102,7 @@
     , raw_doc_data_length(file_data_length)
     , is_locked(false)
 {
-    Object obj;
-    obj.initNull();
-    MemStream *memstr = new MemStream(const_cast<char *>(raw_doc_data), 0, raw_doc_data_length, &obj);
+    MemStream *memstr = new MemStream(const_cast<char *>(raw_doc_data), 0, raw_doc_data_length, Object(objNull));
     GooString goo_owner_password(owner_password.c_str());
     GooString goo_user_password(user_password.c_str());
     doc = new PDFDoc(memstr, &goo_owner_password, &goo_user_password);
@@ -315,9 +311,8 @@
         return std::vector<std::string>();
     }
 
-    Object info;
-    if (!d->doc->getDocInfo(&info)->isDict()) {
-        info.free();
+    Object info = d->doc->getDocInfo();
+    if (!info.isDict()) {
         return std::vector<std::string>();
     }
 
@@ -327,7 +322,6 @@
         keys[i] = std::string(info_dict->getKey(i));
     }
 
-    info.free();
     return keys;
 }
 
diff --git a/cpp/poppler-page.cpp b/cpp/poppler-page.cpp
index b8927b8..a3f8506 100644
--- a/cpp/poppler-page.cpp
+++ b/cpp/poppler-page.cpp
@@ -172,11 +172,10 @@
 page_transition* page::transition() const
 {
     if (!d->transition) {
-        Object o;
-        if (d->page->getTrans(&o)->isDict()) {
+        Object o = d->page->getTrans();
+        if (o.isDict()) {
             d->transition = new page_transition(&o);
         }
-        o.free();
     }
     return d->transition;
 }
diff --git a/fofi/FoFiType1.cc b/fofi/FoFiType1.cc
index 8974cc9..f741d5d 100644
--- a/fofi/FoFiType1.cc
+++ b/fofi/FoFiType1.cc
@@ -302,6 +302,7 @@
 	    if (code >= 0 && code < 256) {
 	      c = *p2;
 	      *p2 = '\0';
+	      gfree(encoding[code]);
 	      encoding[code] = copyString(p);
 	      *p2 = c;
 	    }
diff --git a/glib/poppler-action.cc b/glib/poppler-action.cc
index 809fa58..ad8ed18 100644
--- a/glib/poppler-action.cc
+++ b/glib/poppler-action.cc
@@ -431,9 +431,8 @@
   if (link->hasAnnotRef ()) {
     Ref *ref = link->getAnnotRef ();
 
-    xref->fetch (ref->num, ref->gen, &annotObj);
+    annotObj = xref->fetch (ref->num, ref->gen);
   } else if (link->hasAnnotTitle ()) {
-    Object annots;
     GooString *title = link->getAnnotTitle ();
     int i;
 
@@ -441,52 +440,48 @@
       Page *p = document->doc->getPage (i);
       if (!p) continue;
 
-      if (p->getAnnots (&annots)->isArray ()) {
+      Object annots = p->getAnnotsObject ();
+      if (annots.isArray ()) {
         int j;
 	GBool found = gFalse;
 
 	for (j = 0; j < annots.arrayGetLength () && !found; ++j) {
-          if (annots.arrayGet(j, &annotObj)->isDict()) {
-	    Object obj1;
-
-	    if (!annotObj.dictLookup ("Subtype", &obj1)->isName ("Movie")) {
-	      obj1.free ();
+          annotObj = annots.arrayGet(j);
+          if (annotObj.isDict()) {
+	    Object obj1 = annotObj.dictLookup ("Subtype");
+	    if (!obj1.isName ("Movie")) {
 	      continue;
 	    }
-	    obj1.free ();
 
-	    if (annotObj.dictLookup ("T", &obj1)->isString()) {
+	    obj1 = annotObj.dictLookup ("T");
+	    if (obj1.isString()) {
 	      GooString *t = obj1.getString ();
 
 	      if (title->cmp(t) == 0)
 	        found = gTrue;
 	    }
-	    obj1.free ();
 	  }
 	  if (!found)
-	    annotObj.free ();
+	    annotObj.setToNull ();
 	}
 	if (found) {
-	  annots.free ();
 	  break;
 	} else {
-          annotObj.free ();
+          annotObj.setToNull ();
 	}
       }
-      annots.free ();
     }
   }
 
   if (annotObj.isDict ()) {
     Object tmp;
 
-    annot = new AnnotMovie (document->doc, annotObj.getDict(), &tmp);
+    annot = new AnnotMovie (document->doc, &annotObj, &tmp);
     if (!annot->isOk ()) {
       delete annot;
       annot = NULL;
     }
   }
-  annotObj.free ();
 
   return annot;
 }
diff --git a/glib/poppler-attachment.cc b/glib/poppler-attachment.cc
index 874bffb..5d84595 100644
--- a/glib/poppler-attachment.cc
+++ b/glib/poppler-attachment.cc
@@ -35,7 +35,7 @@
 typedef struct _PopplerAttachmentPrivate PopplerAttachmentPrivate;
 struct _PopplerAttachmentPrivate
 {
-  Object *obj_stream;
+  Object obj_stream;
 };
 
 #define POPPLER_ATTACHMENT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), POPPLER_TYPE_ATTACHMENT, PopplerAttachmentPrivate))
@@ -64,13 +64,7 @@
   PopplerAttachmentPrivate *priv;
 
   priv = POPPLER_ATTACHMENT_GET_PRIVATE (obj);
-
-  if (priv->obj_stream)
-    {
-      priv->obj_stream->free();
-      delete priv->obj_stream;
-      priv->obj_stream = NULL;
-    }
+  priv->obj_stream = Object();
 
   G_OBJECT_CLASS (poppler_attachment_parent_class)->dispose (obj);
 }
@@ -127,10 +121,7 @@
   if (embFile->checksum () && embFile->checksum ()->getLength () > 0)
     attachment->checksum = g_string_new_len (embFile->checksum ()->getCString (),
                                              embFile->checksum ()->getLength ());
-  priv->obj_stream = new Object();
-  priv->obj_stream->initStream(embFile->stream());
-  // Copy the stream
-  embFile->stream()->incRef();
+  priv->obj_stream = embFile->streamObject()->copy();
 
   return attachment;
 }
@@ -243,7 +234,7 @@
 
   g_return_val_if_fail (POPPLER_IS_ATTACHMENT (attachment), FALSE);
 
-  stream = POPPLER_ATTACHMENT_GET_PRIVATE (attachment)->obj_stream->getStream();
+  stream = POPPLER_ATTACHMENT_GET_PRIVATE (attachment)->obj_stream.getStream();
   stream->reset();
 
   do
diff --git a/glib/poppler-document.cc b/glib/poppler-document.cc
index 334f9b6..157a048 100644
--- a/glib/poppler-document.cc
+++ b/glib/poppler-document.cc
@@ -230,7 +230,6 @@
                                 const char  *password,
                                 GError     **error)
 {
-  Object obj;
   PDFDoc *newDoc;
   MemStream *str;
   GooString *password_g;
@@ -240,8 +239,7 @@
   }
   
   // create stream
-  obj.initNull();
-  str = new MemStream(data, 0, length, &obj);
+  str = new MemStream(data, 0, length, Object(objNull));
 
   password_g = poppler_password_to_latin1(password);
   newDoc = new PDFDoc(str, password_g, password_g);
@@ -282,7 +280,6 @@
                                   GCancellable *cancellable,
                                   GError      **error)
 {
-  Object obj;
   PDFDoc *newDoc;
   BaseStream *str;
   GooString *password_g;
@@ -300,12 +297,11 @@
     return NULL;
   }
 
-  obj.initNull();
   if (stream_is_memory_buffer_or_local_file(stream)) {
-    str = new PopplerInputStream(stream, cancellable, 0, gFalse, 0, &obj);
+    str = new PopplerInputStream(stream, cancellable, 0, gFalse, 0, Object(objNull));
   } else {
     CachedFile *cachedFile = new CachedFile(new PopplerCachedFileLoader(stream, cancellable, length), new GooString());
-    str = new CachedFileStream(cachedFile, 0, gFalse, cachedFile->getLength(), &obj);
+    str = new CachedFileStream(cachedFile, 0, gFalse, cachedFile->getLength(), Object(objNull));
   }
 
   password_g = poppler_password_to_latin1(password);
@@ -2410,32 +2406,26 @@
     int i, j;
 
     for (i = 0; i < rb->getLength (); ++i) {
-      Object obj;
       Array *rb_array;
       GList *group = NULL;
 
-      rb->get (i, &obj);
+      Object obj = rb->get (i);
       if (!obj.isArray ()) {
-        obj.free ();
 	continue;
       }
 
       rb_array = obj.getArray ();
       for (j = 0; j < rb_array->getLength (); ++j) {
-        Object ref;
 	OptionalContentGroup *oc;
 
-	rb_array->getNF (j, &ref);
+        Object ref = rb_array->getNF (j);
 	if (!ref.isRef ()) {
-	  ref.free ();
 	  continue;
 	}
 
 	oc = ocg->findOcgByRef (ref.getRef ());
 	group = g_list_prepend (group, oc);
-	ref.free ();
       }
-      obj.free ();
 
       groups = g_list_prepend (groups, group);
     }
@@ -2468,14 +2458,10 @@
   int i;
 
   for (i = 0; i < order->getLength (); ++i) {
-    Object orderItem;
-      
-    order->get (i, &orderItem);
+    Object orderItem = order->get (i);
 
     if (orderItem.isDict ()) {
-      Object ref;
-      
-      order->getNF (i, &ref);
+      Object ref = order->getNF (i);
       if (ref.isRef ()) {
         OptionalContentGroup *oc = ocg->findOcgByRef (ref.getRef ());
 	Layer *layer = layer_new (oc);
@@ -2483,7 +2469,6 @@
 	items = g_list_prepend (items, layer);
 	last_item = layer;
       }
-      ref.free ();
     } else if (orderItem.isArray () && orderItem.arrayGetLength () > 0) {
       if (!last_item) {
         last_item = layer_new (NULL);
@@ -2494,7 +2479,6 @@
     } else if (orderItem.isString ()) {
       last_item->label = _poppler_goo_string_to_utf8 (orderItem.getString ());
     }
-    orderItem.free ();
   }
   
   return g_list_reverse (items);
diff --git a/glib/poppler-input-stream.cc b/glib/poppler-input-stream.cc
index e57e344..cf7a504 100644
--- a/glib/poppler-input-stream.cc
+++ b/glib/poppler-input-stream.cc
@@ -21,8 +21,8 @@
 #include "poppler-input-stream.h"
 
 PopplerInputStream::PopplerInputStream(GInputStream *inputStreamA, GCancellable *cancellableA,
-                                       Goffset startA, GBool limitedA, Goffset lengthA, Object *dictA)
-  : BaseStream(dictA, lengthA)
+                                       Goffset startA, GBool limitedA, Goffset lengthA, Object &&dictA)
+  : BaseStream(std::move(dictA), lengthA)
 {
   inputStream = (GInputStream *)g_object_ref(inputStreamA);
   cancellable = cancellableA ? (GCancellable *)g_object_ref(cancellableA) : NULL;
@@ -44,13 +44,13 @@
 }
 
 BaseStream *PopplerInputStream::copy() {
-  return new PopplerInputStream(inputStream, cancellable, start, limited, length, &dict);
+  return new PopplerInputStream(inputStream, cancellable, start, limited, length, dict.copy());
 }
 
 Stream *PopplerInputStream::makeSubStream(Goffset startA, GBool limitedA,
-                                          Goffset lengthA, Object *dictA)
+                                          Goffset lengthA, Object &&dictA)
 {
-  return new PopplerInputStream(inputStream, cancellable, startA, limitedA, lengthA, dictA);
+  return new PopplerInputStream(inputStream, cancellable, startA, limitedA, lengthA, std::move(dictA));
 }
 
 void PopplerInputStream::reset()
diff --git a/glib/poppler-input-stream.h b/glib/poppler-input-stream.h
index 39bbe01..536487a 100644
--- a/glib/poppler-input-stream.h
+++ b/glib/poppler-input-stream.h
@@ -31,11 +31,11 @@
 public:
 
   PopplerInputStream(GInputStream *inputStream, GCancellable *cancellableA,
-                     Goffset startA, GBool limitedA, Goffset lengthA, Object *dictA);
+                     Goffset startA, GBool limitedA, Goffset lengthA, Object &&dictA);
   ~PopplerInputStream();
   BaseStream *copy() override;
   Stream *makeSubStream(Goffset start, GBool limited,
-                        Goffset lengthA, Object *dictA) override;
+                        Goffset lengthA, Object &&dictA) override;
   StreamKind getKind() override { return strWeird; }
   void reset() override;
   void close() override;
diff --git a/glib/poppler-media.cc b/glib/poppler-media.cc
index 5712371..8634af4 100644
--- a/glib/poppler-media.cc
+++ b/glib/poppler-media.cc
@@ -40,7 +40,7 @@
   gchar  *filename;
 
   gchar  *mime_type;
-  Stream *stream;
+  Object stream;
 };
 
 struct _PopplerMediaClass
@@ -65,10 +65,7 @@
     media->mime_type = NULL;
   }
 
-  if (media->stream) {
-    media->stream->decRef();
-    media->stream = NULL;
-  }
+  media->stream = Object();
 
   G_OBJECT_CLASS (poppler_media_parent_class)->finalize (object);
 }
@@ -98,7 +95,7 @@
   if (poppler_media->getIsEmbedded()) {
     GooString* mime_type;
 
-    media->stream = poppler_media->getEmbbededStream();
+    media->stream = poppler_media->getEmbbededStreamObject()->copy();
     mime_type = poppler_media->getContentType();
     if (mime_type)
       media->mime_type = g_strdup (mime_type->getCString());
@@ -124,7 +121,7 @@
 poppler_media_get_filename (PopplerMedia *poppler_media)
 {
   g_return_val_if_fail (POPPLER_IS_MEDIA (poppler_media), NULL);
-  g_return_val_if_fail (poppler_media->stream == NULL, NULL);
+  g_return_val_if_fail (!poppler_media->stream.isStream(), NULL);
 
   return poppler_media->filename;
 }
@@ -147,7 +144,7 @@
 {
   g_return_val_if_fail (POPPLER_IS_MEDIA (poppler_media), FALSE);
 
-  return poppler_media->stream != NULL;
+  return poppler_media->stream.isStream();
 }
 
 /**
@@ -215,7 +212,7 @@
   FILE *f;
 
   g_return_val_if_fail (POPPLER_IS_MEDIA (poppler_media), FALSE);
-  g_return_val_if_fail (poppler_media->stream != NULL, FALSE);
+  g_return_val_if_fail (poppler_media->stream.isStream(), FALSE);
 
   f = g_fopen (filename, "wb");
 
@@ -281,9 +278,9 @@
   gboolean eof_reached = FALSE;
 
   g_return_val_if_fail (POPPLER_IS_MEDIA (poppler_media), FALSE);
-  g_return_val_if_fail (poppler_media->stream != NULL, FALSE);
+  g_return_val_if_fail (poppler_media->stream.isStream(), FALSE);
 
-  stream = poppler_media->stream;
+  stream = poppler_media->stream.getStream();
   stream->reset();
 
   do
diff --git a/glib/poppler-movie.cc b/glib/poppler-movie.cc
index 791cda7..1e82af7 100644
--- a/glib/poppler-movie.cc
+++ b/glib/poppler-movie.cc
@@ -84,11 +84,8 @@
 
   movie->filename = g_strdup (poppler_movie->getFileName()->getCString());
   if (poppler_movie->getShowPoster()) {
-    Object tmp;
-
-    poppler_movie->getPoster(&tmp);
+    Object tmp = poppler_movie->getPoster();
     movie->need_poster = (!tmp.isRef() && !tmp.isStream());
-    tmp.free();
   }
 
   movie->show_controls = poppler_movie->getActivationParameters()->showControls;
diff --git a/glib/poppler-page.cc b/glib/poppler-page.cc
index 3d63bfd..a44edac 100644
--- a/glib/poppler-page.cc
+++ b/glib/poppler-page.cc
@@ -184,12 +184,11 @@
 {
   PageTransition *trans;
   PopplerPageTransition *transition;
-  Object obj;
-  
+
   g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
 
-  trans = new PageTransition (page->page->getTrans (&obj));
-  obj.free ();
+  Object obj = page->page->getTrans ();
+  trans = new PageTransition (&obj);
 
   if (!trans->isOk ()) {
     delete trans;
@@ -588,7 +587,6 @@
 				 int         *width,
 				 int         *height)
 {
-  Object thumb;
   Dict *dict;
   gboolean retval = FALSE;
 
@@ -596,10 +594,9 @@
   g_return_val_if_fail (width != NULL, FALSE);
   g_return_val_if_fail (height != NULL, FALSE);
 
-  page->page->getThumb (&thumb);
+  Object thumb = page->page->getThumb ();
   if (!thumb.isStream ())
     {
-      thumb.free ();
       return FALSE;
     }
 
@@ -611,8 +608,6 @@
       dict->lookupInt ("Height", "H", height))
     retval = TRUE;
 
-  thumb.free ();
-
   return retval;
 }
 
diff --git a/glib/poppler-structure-element.cc b/glib/poppler-structure-element.cc
index c626999..70dfd50 100644
--- a/glib/poppler-structure-element.cc
+++ b/glib/poppler-structure-element.cc
@@ -1213,9 +1213,8 @@
       g_assert (object->arrayGetLength () == 4);
       for (guint i = 0; i < 4; i++)
         {
-          Object item;
-          values[i] = name_to_enum<PopplerStructureBorderStyle> (object->arrayGet (i, &item));
-          item.free ();
+          Object item = object->arrayGet (i);
+          values[i] = name_to_enum<PopplerStructureBorderStyle> (&item);
         }
     }
   else
@@ -1261,9 +1260,7 @@
 
   for (guint i = 0; i < *n_values; i++)
     {
-      Object item;
-      doubles[i] = object->arrayGet (i, &item)->getNum ();
-      item.free ();
+      doubles[i] = object->arrayGet (i).getNum ();
     }
 }
 
@@ -1273,16 +1270,9 @@
   g_assert (color != NULL);
   g_assert (object->isArray () && object->arrayGetLength () != 3);
 
-  Object item;
-
-  color->red = object->arrayGet (0, &item)->getNum () * 65535;
-  item.free ();
-
-  color->green = object->arrayGet (1, &item)->getNum () * 65535;
-  item.free ();
-
-  color->blue = object->arrayGet (2, &item)->getNum () * 65535;
-  item.free ();
+  color->red = object->arrayGet (0).getNum () * 65535;
+  color->green = object->arrayGet (1).getNum () * 65535;
+  color->blue = object->arrayGet (2).getNum () * 65535;
 }
 
 /**
@@ -1377,9 +1367,8 @@
       // One color per side.
       for (guint i = 0; i < 4; i++)
         {
-          Object item;
-          convert_color (value->arrayGet (i, &item), &colors[i]);
-          item.free ();
+          Object item = value->arrayGet (i);
+          convert_color (&item, &colors[i]);
         }
     }
   else
@@ -1403,9 +1392,7 @@
       g_assert (object->arrayGetLength () == 4);
       for (guint i = 0; i < 4; i++)
         {
-          Object item;
-          value[i] = object->arrayGet (i, &item)->getNum ();
-          item.free ();
+          value[i] = object->arrayGet (i).getNum ();
         }
     }
   else
@@ -2175,16 +2162,14 @@
 
   for (guint i = 0; i < n_values; i++)
     {
-      Object item;
+      Object item = value->arrayGet (i);
 
-      if (value->arrayGet (i, &item)->isString ())
+      if (item.isString ())
         result[i] = _poppler_goo_string_to_utf8 (item.getString ());
       else if (item.isName ())
         result[i] = g_strdup (item.getName ());
       else
         g_assert_not_reached ();
-
-      item.free ();
     }
 
   return result;
diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 974b098..bda5a90 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -166,10 +166,10 @@
 }
 
 static AnnotExternalDataType parseAnnotExternalData(Dict* dict) {
-  Object obj1;
   AnnotExternalDataType type;
 
-  if (dict->lookup("Subtype", &obj1)->isName()) {
+  Object obj1 = dict->lookup("Subtype");
+  if (obj1.isName()) {
     const char *typeName = obj1.getName();
 
     if (!strcmp(typeName, "Markup3D")) {
@@ -180,7 +180,6 @@
   } else {
     type = annotExternalDataMarkupUnknown;
   }
-  obj1.free();
 
   return type;
 }
@@ -190,14 +189,10 @@
   if (array->getLength() == 4) {
     // deltas
     Object obj1;
-    double dx1 = (array->get(0, &obj1)->isNum() ? obj1.getNum() : 0);
-    obj1.free();
-    double dy1 = (array->get(1, &obj1)->isNum() ? obj1.getNum() : 0);
-    obj1.free();
-    double dx2 = (array->get(2, &obj1)->isNum() ? obj1.getNum() : 0);
-    obj1.free();
-    double dy2 = (array->get(3, &obj1)->isNum() ? obj1.getNum() : 0);
-    obj1.free();
+    double dx1 = (obj1 = array->get(0), obj1.isNum() ? obj1.getNum() : 0);
+    double dy1 = (obj1 = array->get(1), obj1.isNum() ? obj1.getNum() : 0);
+    double dx2 = (obj1 = array->get(2), obj1.isNum() ? obj1.getNum() : 0);
+    double dy2 = (obj1 = array->get(3), obj1.isNum() ? obj1.getNum() : 0);
 
     // checking that the numbers are valid (i.e. >= 0),
     // and that applying the differences still give us a valid rect
@@ -215,10 +210,10 @@
 }
 
 static LinkAction* getAdditionalAction(Annot::AdditionalActionsType type, Object *additionalActions, PDFDoc *doc) {
-  Object additionalActionsObject;
-  LinkAction *linkAction = NULL;
+  LinkAction *linkAction = nullptr;
+  Object additionalActionsObject = additionalActions->fetch(doc->getXRef());
 
-  if (additionalActions->fetch(doc->getXRef(), &additionalActionsObject)->isDict()) {
+  if (additionalActionsObject.isDict()) {
     const char *key = (type == Annot::actionCursorEntering ? "E" :
                        type == Annot::actionCursorLeaving ?  "X" :
                        type == Annot::actionMousePressed ?   "D" :
@@ -230,37 +225,29 @@
                        type == Annot::actionPageVisible ?   "PV" :
                        type == Annot::actionPageInvisible ? "PI" : NULL);
 
-    Object actionObject;
-
-    if (additionalActionsObject.dictLookup(key, &actionObject)->isDict())
+    Object actionObject = additionalActionsObject.dictLookup(key);
+    if (actionObject.isDict())
       linkAction = LinkAction::parseAction(&actionObject, doc->getCatalog()->getBaseURI());
-    actionObject.free();
   }
 
-  additionalActionsObject.free();
-
   return linkAction;
 }
 
 static LinkAction* getFormAdditionalAction(Annot::FormAdditionalActionsType type, Object *additionalActions, PDFDoc *doc) {
-  Object additionalActionsObject;
-  LinkAction *linkAction = NULL;
+  LinkAction *linkAction = nullptr;
+  Object additionalActionsObject = additionalActions->fetch(doc->getXRef());
 
-  if (additionalActions->fetch(doc->getXRef(), &additionalActionsObject)->isDict()) {
+  if (additionalActionsObject.isDict()) {
     const char *key = (type == Annot::actionFieldModified ?  "K" :
                        type == Annot::actionFormatField ?    "F" :
                        type == Annot::actionValidateField ?  "V" :
                        type == Annot::actionCalculateField ? "C" : NULL);
 
-    Object actionObject;
-
-    if (additionalActionsObject.dictLookup(key, &actionObject)->isDict())
+    Object actionObject = additionalActionsObject.dictLookup(key);
+    if (actionObject.isDict())
       linkAction = LinkAction::parseAction(&actionObject, doc->getCatalog()->getBaseURI());
-    actionObject.free();
   }
 
-  additionalActionsObject.free();
-
   return linkAction;
 }
 
@@ -271,7 +258,8 @@
 AnnotBorderEffect::AnnotBorderEffect(Dict *dict) {
   Object obj1;
 
-  if (dict->lookup("S", &obj1)->isName()) {
+  obj1 = dict->lookup("S");
+  if (obj1.isName()) {
     const char *effectName = obj1.getName();
 
     if (!strcmp(effectName, "C"))
@@ -281,14 +269,13 @@
   } else {
     effectType = borderEffectNoEffect;
   }
-  obj1.free();
 
-  if ((dict->lookup("I", &obj1)->isNum()) && effectType == borderEffectCloudy) {
+  obj1 = dict->lookup("I");
+  if (obj1.isNum() && effectType == borderEffectCloudy) {
     intensity = obj1.getNum();
   } else {
     intensity = 0;
   }
-  obj1.free();
 }
 
 //------------------------------------------------------------------------
@@ -351,22 +338,21 @@
   tempCoords = (AnnotCoord **) gmallocn (tempLength, sizeof(AnnotCoord *));
   memset(tempCoords, 0, tempLength * sizeof(AnnotCoord *));
   for (int i = 0; i < tempLength && correct; i++) {
-    Object obj1;
     double x = 0, y = 0;
 
-    if (array->get(i * 2, &obj1)->isNum()) {
+    Object obj1 = array->get(i * 2);
+    if (obj1.isNum()) {
       x = obj1.getNum();
     } else {
       correct = gFalse;
     }
-    obj1.free();
 
-    if (array->get((i * 2) + 1, &obj1)->isNum()) {
+    obj1 = array->get((i * 2) + 1);
+    if (obj1.isNum()) {
       y = obj1.getNum();
     } else {
       correct = gFalse;
     }
-    obj1.free();
 
     if (!correct) {
       for (int j = i - 1; j >= 0; j--)
@@ -424,16 +410,14 @@
 
     for (i = 0; i < quadsLength; i++) {
       for (int j = 0; j < 8; j++) {
-        Object obj;
-        if (array->get(i * 8 + j, &obj)->isNum()) {
+        Object obj = array->get(i * 8 + j);
+        if (obj.isNum()) {
           quadArray[j] = obj.getNum();
         } else {
             correct = gFalse;
-	    obj.free();
 	    error (errSyntaxError, -1, "Invalid QuadPoint in annot");
 	    break;
         }
-        obj.free();
       }
 
       if (!correct)
@@ -540,13 +524,11 @@
 
   // TODO: check not all zero (Line Dash Pattern Page 217 PDF 8.1)
   for (int i = 0; i < tempLength && i < DASH_LIMIT && correct; i++) {
-    Object obj1;
-
-    if (dashObj->arrayGet(i, &obj1)->isNum()) {
+    Object obj1 = dashObj->arrayGet(i);
+    if (obj1.isNum()) {
       tempDash[i] = obj1.getNum();
 
       correct = tempDash[i] >= 0;
-      obj1.free();
     }
   }
 
@@ -583,30 +565,30 @@
   if (arrayLength == 3 || arrayLength == 4) {
     // implementation note 81 in Appendix H.
 
-    if (array->get(0, &obj1)->isNum())
+    obj1 = array->get(0);
+    if (obj1.isNum())
       horizontalCorner = obj1.getNum();
     else
       correct = gFalse;
-    obj1.free();
 
-    if (array->get(1, &obj1)->isNum())
+    obj1 = array->get(1);
+    if (obj1.isNum())
       verticalCorner = obj1.getNum();
     else
       correct = gFalse;
-    obj1.free();
 
-    if (array->get(2, &obj1)->isNum())
+    obj1 = array->get(2);
+    if (obj1.isNum())
       width = obj1.getNum();
     else
       correct = gFalse;
-    obj1.free();
 
     if (arrayLength == 4) {
-      if (array->get(3, &obj1)->isArray())
+      obj1 = array->get(3);
+      if (obj1.isArray())
         correct = parseDashArray(&obj1);
       else
         correct = gFalse;
-      obj1.free();
     }
   } else {
     correct = gFalse;
@@ -617,21 +599,22 @@
   }
 }
 
-void AnnotBorderArray::writeToObject(XRef *xref, Object *obj1) const {
-  Object obj2;
-
-  obj1->initArray(xref);
-  obj1->arrayAdd(obj2.initReal(horizontalCorner));
-  obj1->arrayAdd(obj2.initReal(verticalCorner));
-  obj1->arrayAdd(obj2.initReal(width));
+Object AnnotBorderArray::writeToObject(XRef *xref) const {
+  Array *borderArray = new Array(xref);
+  borderArray->add(Object(horizontalCorner));
+  borderArray->add(Object(verticalCorner));
+  borderArray->add(Object(width));
 
   if (dashLength > 0) {
-    Object obj3;
+    Array *a = new Array(xref);
 
-    obj1->arrayAdd(obj3.initArray(xref));
     for (int i = 0; i < dashLength; i++)
-      obj3.arrayAdd(obj2.initReal(dash[i]));
+      a->add(Object(dash[i]));
+
+    borderArray->add(Object(a));
   }
+
+  return Object(borderArray);
 }
 
 //------------------------------------------------------------------------
@@ -650,8 +633,8 @@
   // that behaviour by veryifying both entries exist
   // otherwise we set the borderWidth to 0
   // --jrmuizel
-  dict->lookup("W", &obj1);
-  dict->lookup("S", &obj2);
+  obj1 = dict->lookup("W");
+  obj2 = dict->lookup("S");
   if (obj1.isNum() && obj2.isName()) {
     const char *styleName = obj2.getName();
 
@@ -673,13 +656,11 @@
   } else {
     width = 0;
   }
-  obj2.free();
-  obj1.free();
 
   if (style == borderDashed) {
-    if (dict->lookup("D", &obj1)->isArray())
+    obj1 = dict->lookup("D");
+  if (obj1.isArray())
       parseDashArray(&obj1);
-    obj1.free();
 
     if (!dash) {
       dashLength = 1;
@@ -706,19 +687,18 @@
   return "S";
 }
 
-void AnnotBorderBS::writeToObject(XRef *xref, Object *obj1) const {
-  Object obj2;
-
-  obj1->initDict(xref);
-  obj1->dictSet("W", obj2.initReal(width));
-  obj1->dictSet("S", obj2.initName(getStyleName()));
+Object AnnotBorderBS::writeToObject(XRef *xref) const {
+  Dict *dict = new Dict(xref);
+  dict->set("W", Object(width));
+  dict->set("S", Object(objName, getStyleName()));
   if (style == borderDashed && dashLength > 0) {
-    Object obj3;
+    Array *a = new Array(xref);
 
-    obj1->dictSet("D", obj3.initArray(xref));
     for (int i = 0; i < dashLength; i++)
-      obj3.arrayAdd(obj2.initReal(dash[i]));
+      a->add(Object(dash[i]));
+    dict->set("D", Object(a));
   }
+  return Object(dict);
 }
 
 //------------------------------------------------------------------------
@@ -763,9 +743,8 @@
     length = 4;
 
   for (i = 0; i < length; i++) {
-    Object obj1;
-
-    if (array->get(i, &obj1)->isNum()) {
+    Object obj1 = array->get(i);
+    if (obj1.isNum()) {
       values[i] = obj1.getNum();
 
       if (values[i] < 0 || values[i] > 1)
@@ -773,7 +752,6 @@
     } else {
       values[i] = 0;
     }
-    obj1.free();
   }
 
   if (adjust != 0)
@@ -797,16 +775,14 @@
   }
 }
 
-void AnnotColor::writeToObject(XRef *xref, Object *obj1) const {
-  Object obj2;
-  int i;
-
+Object AnnotColor::writeToObject(XRef *xref) const {
   if (length == 0) {
-    obj1->initNull(); // Transparent (no color)
+    return Object(objNull); // Transparent (no color)
   } else {
-    obj1->initArray(xref);
-    for (i = 0; i < length; ++i)
-      obj1->arrayAdd( obj2.initReal( values[i] ) );
+    Array *a = new Array(xref);
+    for (int i = 0; i < length; ++i)
+      a->add( Object( values[i] ) );
+    return Object(a);
   }
 }
 
@@ -817,7 +793,8 @@
 AnnotIconFit::AnnotIconFit(Dict* dict) {
   Object obj1;
 
-  if (dict->lookup("SW", &obj1)->isName()) {
+  obj1 = dict->lookup("SW");
+  if (obj1.isName()) {
     const char *scaleName = obj1.getName();
 
     if(!strcmp(scaleName, "B")) {
@@ -832,9 +809,9 @@
   } else {
     scaleWhen = scaleAlways;
   }
-  obj1.free();
 
-  if (dict->lookup("S", &obj1)->isName()) {
+  obj1 = dict->lookup("S");
+  if (obj1.isName()) {
     const char *scaleName = obj1.getName();
 
     if(!strcmp(scaleName, "A")) {
@@ -845,14 +822,12 @@
   } else {
     scale = scaleProportional;
   }
-  obj1.free();
 
-  if (dict->lookup("A", &obj1)->isArray() && obj1.arrayGetLength() == 2) {
+  obj1 = dict->lookup("A");
+  if (obj1.isArray() && obj1.arrayGetLength() == 2) {
     Object obj2;
-    (obj1.arrayGet(0, &obj2)->isNum() ? left = obj2.getNum() : left = 0);
-    obj2.free();
-    (obj1.arrayGet(1, &obj2)->isNum() ? bottom = obj2.getNum() : bottom = 0);
-    obj2.free();
+    (obj2 = obj1.arrayGet(0), obj2.isNum() ? left = obj2.getNum() : left = 0);
+    (obj2 = obj1.arrayGet(1), obj2.isNum() ? bottom = obj2.getNum() : bottom = 0);
 
     if (left < 0 || left > 1)
       left = 0.5;
@@ -863,14 +838,13 @@
   } else {
     left = bottom = 0.5;
   }
-  obj1.free();
 
-  if (dict->lookup("FB", &obj1)->isBool()) {
+  obj1 = dict->lookup("FB");
+  if (obj1.isBool()) {
     fullyBounds = obj1.getBool();
   } else {
     fullyBounds = gFalse;
   }
-  obj1.free();
 }
 
 //------------------------------------------------------------------------
@@ -881,55 +855,54 @@
   assert(dict->isDict());
   doc = docA;
   xref = docA->getXRef();
-  dict->copy(&appearDict);
+  appearDict = dict->copy();
 }
 
 AnnotAppearance::~AnnotAppearance() {
-  appearDict.free();
 }
 
-void AnnotAppearance::getAppearanceStream(AnnotAppearanceType type, const char *state, Object *dest) {
-  Object apData, stream;
-  apData.initNull();
+Object AnnotAppearance::getAppearanceStream(AnnotAppearanceType type, const char *state) {
+  Object apData;
 
   // Obtain dictionary or stream associated to appearance type
   switch (type) {
   case appearRollover:
-    if (appearDict.dictLookupNF("R", &apData)->isNull())
-      appearDict.dictLookupNF("N", &apData);
+    apData = appearDict.dictLookupNF("R");
+    if (apData.isNull())
+      apData = appearDict.dictLookupNF("N");
     break;
   case appearDown:
-    if (appearDict.dictLookupNF("D", &apData)->isNull())
-      appearDict.dictLookupNF("N", &apData);
+    apData = appearDict.dictLookupNF("D");
+    if (apData.isNull())
+      apData = appearDict.dictLookupNF("N");
     break;
   case appearNormal:
-    appearDict.dictLookupNF("N", &apData);
+    apData = appearDict.dictLookupNF("N");
     break;
   }
 
-  dest->initNull();
+  Object res;
   if (apData.isDict() && state)
-    apData.dictLookupNF(state, dest);
+    res = apData.dictLookupNF(state);
   else if (apData.isRef())
-    apData.copy(dest);
-  apData.free();
+    res = apData.copy();
+
+  return res;
 }
 
 GooString * AnnotAppearance::getStateKey(int i) {
-  Object obj1;
   GooString * res = NULL;
-  if (appearDict.dictLookupNF("N", &obj1)->isDict())
+  Object obj1 = appearDict.dictLookupNF("N");
+  if (obj1.isDict())
     res = new GooString(obj1.dictGetKey(i));
-  obj1.free();
   return res;
 }
 
 int AnnotAppearance::getNumStates() {
-  Object obj1;
   int res = 0;
-  if (appearDict.dictLookupNF("N", &obj1)->isDict())
+  Object obj1 = appearDict.dictLookupNF("N");
+  if (obj1.isDict())
     res = obj1.dictGetLength();
-  obj1.free();
   return res;
 }
 
@@ -943,15 +916,13 @@
   } else if (stateObj->isDict()) { // Test each value
     const int size = stateObj->dictGetLength();
     for (int i = 0; i < size; ++i) {
-      Object obj1;
-      stateObj->dictGetValNF(i, &obj1);
+      Object obj1 = stateObj->dictGetValNF(i);
       if (obj1.isRef()) {
         Ref r = obj1.getRef();
         if (r.num == refToStream.num && r.gen == refToStream.gen) {
           return gTrue;
         }
       }
-      obj1.free();
     }
   }
   return gFalse; // Not found
@@ -963,21 +934,18 @@
   GBool found;
 
   // Scan each state's ref/subdictionary
-  appearDict.dictLookupNF("N", &obj1);
+  obj1 = appearDict.dictLookupNF("N");
   found = referencesStream(&obj1, refToStream);
-  obj1.free();
   if (found)
     return gTrue;
 
-  appearDict.dictLookupNF("R", &obj1);
+  obj1 = appearDict.dictLookupNF("R");
   found = referencesStream(&obj1, refToStream);
-  obj1.free();
   if (found)
     return gTrue;
 
-  appearDict.dictLookupNF("D", &obj1);
+  obj1 = appearDict.dictLookupNF("D");
   found = referencesStream(&obj1, refToStream);
-  obj1.free();
   return found;
 }
 
@@ -1011,27 +979,22 @@
   } else if (obj1->isDict()) {
     const int size = obj1->dictGetLength();
     for (int i = 0; i < size; ++i) {
-      Object obj2;
-      obj1->dictGetValNF(i, &obj2);
+      Object obj2 = obj1->dictGetValNF(i);
       if (obj2.isRef()) {
         removeStream(obj2.getRef());
       }
-      obj2.free();
     }
   }
 }
 
 void AnnotAppearance::removeAllStreams() {
   Object obj1;
-  appearDict.dictLookupNF("N", &obj1);
+  obj1 = appearDict.dictLookupNF("N");
   removeStateStreams(&obj1);
-  obj1.free();
-  appearDict.dictLookupNF("R", &obj1);
+  obj1 = appearDict.dictLookupNF("R");
   removeStateStreams(&obj1);
-  obj1.free();
-  appearDict.dictLookupNF("D", &obj1);
+  obj1 = appearDict.dictLookupNF("D");
   removeStateStreams(&obj1);
-  obj1.free();
 }
 
 //------------------------------------------------------------------------
@@ -1041,14 +1004,15 @@
 AnnotAppearanceCharacs::AnnotAppearanceCharacs(Dict *dict) {
   Object obj1;
 
-  if (dict->lookup("R", &obj1)->isInt()) {
+  obj1 = dict->lookup("R");
+  if (obj1.isInt()) {
     rotation = obj1.getInt();
   } else {
     rotation = 0;
   }
-  obj1.free();
 
-  if (dict->lookup("BC", &obj1)->isArray()) {
+  obj1 = dict->lookup("BC");
+  if (obj1.isArray()) {
     Array *colorComponents = obj1.getArray();
     if (colorComponents->getLength() > 0) {
       borderColor = new AnnotColor(colorComponents);
@@ -1058,9 +1022,9 @@
   } else {
     borderColor = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("BG", &obj1)->isArray()) {
+  obj1 = dict->lookup("BG");
+  if (obj1.isArray()) {
     Array *colorComponents = obj1.getArray();
     if (colorComponents->getLength() > 0) {
       backColor = new AnnotColor(colorComponents);
@@ -1070,42 +1034,41 @@
   } else {
     backColor = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("CA", &obj1)->isString()) {
+  obj1 = dict->lookup("CA");
+  if (obj1.isString()) {
     normalCaption = new GooString(obj1.getString());
   } else {
     normalCaption = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("RC", &obj1)->isString()) {
+  obj1 = dict->lookup("RC");
+  if (obj1.isString()) {
     rolloverCaption = new GooString(obj1.getString());
   } else {
     rolloverCaption = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("AC", &obj1)->isString()) {
+  obj1 = dict->lookup("AC");
+  if (obj1.isString()) {
     alternateCaption = new GooString(obj1.getString());
   } else {
     alternateCaption = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("IF", &obj1)->isDict()) {
+  obj1 = dict->lookup("IF");
+  if (obj1.isDict()) {
     iconFit = new AnnotIconFit(obj1.getDict());
   } else {
     iconFit = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("TP", &obj1)->isInt()) {
+  obj1 = dict->lookup("TP");
+  if (obj1.isInt()) {
     position = (AnnotAppearanceCharacsTextPos) obj1.getInt();
   } else {
     position = captionNoIcon;
   }
-  obj1.free();
 }
 
 AnnotAppearanceCharacs::~AnnotAppearanceCharacs() {
@@ -1185,40 +1148,36 @@
 //------------------------------------------------------------------------
 
 Annot::Annot(PDFDoc *docA, PDFRectangle *rectA) {
-  Object obj1;
 
   refCnt = 1;
   flags = flagUnknown;
   type = typeUnknown;
 
-  obj1.initArray (docA->getXRef());
-  Object obj2;
-  obj1.arrayAdd (obj2.initReal (rectA->x1));
-  obj1.arrayAdd (obj2.initReal (rectA->y1));
-  obj1.arrayAdd (obj2.initReal (rectA->x2));
-  obj1.arrayAdd (obj2.initReal (rectA->y2));
-  obj2.free ();
+  Array *a = new Array(docA->getXRef());
+  a->add(Object(rectA->x1));
+  a->add(Object(rectA->y1));
+  a->add(Object(rectA->x2));
+  a->add(Object(rectA->y2));
 
-  annotObj.initDict (docA->getXRef());
-  annotObj.dictSet ("Type", obj2.initName ("Annot"));
-  annotObj.dictSet ("Rect", &obj1);
-  // obj1 is owned by the dict
+  annotObj = Object(new Dict(docA->getXRef()));
+  annotObj.dictSet ("Type", Object(objName, "Annot"));
+  annotObj.dictSet ("Rect", Object(a));
 
   ref = docA->getXRef()->addIndirectObject (&annotObj);
 
   initialize (docA, annotObj.getDict());
 }
 
-Annot::Annot(PDFDoc *docA, Dict *dict) {
+Annot::Annot(PDFDoc *docA, Object *dictObject) {
   refCnt = 1;
   hasRef = false;
   flags = flagUnknown;
   type = typeUnknown;
-  annotObj.initDict (dict);
-  initialize (docA, dict);
+  annotObj = dictObject->copy();
+  initialize (docA, dictObject->getDict());
 }
 
-Annot::Annot(PDFDoc *docA, Dict *dict, Object *obj) {
+Annot::Annot(PDFDoc *docA, Object *dictObject, Object *obj) {
   refCnt = 1;
   if (obj->isRef()) {
     hasRef = gTrue;
@@ -1228,12 +1187,12 @@
   }
   flags = flagUnknown;
   type = typeUnknown;
-  annotObj.initDict (dict);
-  initialize (docA, dict);
+  annotObj = dictObject->copy();
+  initialize (docA, dictObject->getDict());
 }
 
 void Annot::initialize(PDFDoc *docA, Dict *dict) {
-  Object apObj, asObj, obj1, obj2;
+  Object apObj, asObj, obj1;
 
   ok = gTrue;
   doc = docA;
@@ -1244,20 +1203,17 @@
   appearBuf = NULL;
   fontSize = 0;
 
-  appearance.initNull();
+  appearance.setToNull();
 
   //----- parse the rectangle
   rect = new PDFRectangle();
-  if (dict->lookup("Rect", &obj1)->isArray() && obj1.arrayGetLength() == 4) {
+  obj1 = dict->lookup("Rect");
+  if (obj1.isArray() && obj1.arrayGetLength() == 4) {
     Object obj2;
-    (obj1.arrayGet(0, &obj2)->isNum() ? rect->x1 = obj2.getNum() : rect->x1 = 0);
-    obj2.free();
-    (obj1.arrayGet(1, &obj2)->isNum() ? rect->y1 = obj2.getNum() : rect->y1 = 0);
-    obj2.free();
-    (obj1.arrayGet(2, &obj2)->isNum() ? rect->x2 = obj2.getNum() : rect->x2 = 1);
-    obj2.free();
-    (obj1.arrayGet(3, &obj2)->isNum() ? rect->y2 = obj2.getNum() : rect->y2 = 1);
-    obj2.free();
+    (obj2 = obj1.arrayGet(0), obj2.isNum() ? rect->x1 = obj2.getNum() : rect->x1 = 0);
+    (obj2 = obj1.arrayGet(1), obj2.isNum() ? rect->y1 = obj2.getNum() : rect->y1 = 0);
+    (obj2 = obj1.arrayGet(2), obj2.isNum() ? rect->x2 = obj2.getNum() : rect->x2 = 1);
+    (obj2 = obj1.arrayGet(3), obj2.isNum() ? rect->y2 = obj2.getNum() : rect->y2 = 1);
 
     if (rect->x1 > rect->x2) {
       double t = rect->x1;
@@ -1276,56 +1232,54 @@
     error(errSyntaxError, -1, "Bad bounding box for annotation");
     ok = gFalse;
   }
-  obj1.free();
 
-  if (dict->lookup("Contents", &obj1)->isString()) {
+  obj1 = dict->lookup("Contents");
+  if (obj1.isString()) {
     contents = obj1.getString()->copy();
   } else {
     contents = new GooString();
   }
-  obj1.free();
 
   // Note: This value is overwritten by Annots ctor
-  if (dict->lookupNF("P", &obj1)->isRef()) {
+  obj1 = dict->lookupNF("P");
+  if (obj1.isRef()) {
     Ref ref = obj1.getRef();
 
     page = doc->getCatalog()->findPage (ref.num, ref.gen);
   } else {
     page = 0;
   }
-  obj1.free();
 
-  if (dict->lookup("NM", &obj1)->isString()) {
+  obj1 = dict->lookup("NM");
+  if (obj1.isString()) {
     name = obj1.getString()->copy();
   } else {
     name = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("M", &obj1)->isString()) {
+  obj1 = dict->lookup("M");
+  if (obj1.isString()) {
     modified = obj1.getString()->copy();
   } else {
     modified = NULL;
   }
-  obj1.free();
 
   //----- get the flags
-  if (dict->lookup("F", &obj1)->isInt()) {
+  obj1 = dict->lookup("F");
+  if (obj1.isInt()) {
     flags |= obj1.getInt();
   } else {
     flags = flagUnknown;
   }
-  obj1.free();
 
   //----- get the annotation appearance dictionary
-  dict->lookup("AP", &apObj);
+  apObj = dict->lookup("AP");
   if (apObj.isDict()) {
     appearStreams = new AnnotAppearance(doc, &apObj);
   }
-  apObj.free();
 
   //----- get the appearance state
-  dict->lookup("AS", &asObj);
+  asObj = dict->lookup("AS");
   if (asObj.isName()) {
     appearState = new GooString(asObj.getName());
   } else if (appearStreams && appearStreams->getNumStates() != 0) {
@@ -1340,11 +1294,10 @@
   if (!appearState) {
     appearState = new GooString("Off");
   }
-  asObj.free();
 
   //----- get the annotation appearance
   if (appearStreams) {
-    appearStreams->getAppearanceStream(AnnotAppearance::appearNormal, appearState->getCString(), &appearance);
+    appearance = appearStreams->getAppearanceStream(AnnotAppearance::appearNormal, appearState->getCString());
   }
 
   //----- parse the border style
@@ -1352,27 +1305,27 @@
   // the border shall be drawn as a solid line with a width of 1 point. But acroread
   // seems to ignore the Border entry for annots that can't have a BS entry. So, we only
   // follow this rule for annots tha can have a BS entry.
-  if (dict->lookup("Border", &obj1)->isArray())
+  obj1 = dict->lookup("Border");
+  if (obj1.isArray())
     border = new AnnotBorderArray(obj1.getArray());
   else
     border = NULL;
-  obj1.free();
 
-  if (dict->lookup("C", &obj1)->isArray()) {
+  obj1 = dict->lookup("C");
+  if (obj1.isArray()) {
     color = new AnnotColor(obj1.getArray());
   } else {
     color = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("StructParent", &obj1)->isInt()) {
+  obj1 = dict->lookup("StructParent");
+  if (obj1.isInt()) {
     treeKey = obj1.getInt();
   } else {
     treeKey = 0;
   }
-  obj1.free();
 
-  dict->lookupNF("OC", &oc);
+  oc = dict->lookupNF("OC");
 
 #if MULTITHREADED
   gInitMutex(&mutex);
@@ -1391,8 +1344,6 @@
 }
 
 void Annot::setRect(double x1, double y1, double x2, double y2) {
-  Object obj1, obj2;
-
   if (x1 < x2) {
     rect->x1 = x1;
     rect->x2 = x2;
@@ -1409,13 +1360,13 @@
     rect->y2 = y1;
   }
 
-  obj1.initArray (xref);
-  obj1.arrayAdd (obj2.initReal (rect->x1));
-  obj1.arrayAdd (obj2.initReal (rect->y1));
-  obj1.arrayAdd (obj2.initReal (rect->x2));
-  obj1.arrayAdd (obj2.initReal (rect->y2));
+  Array *a = new Array(xref);
+  a->add(Object(rect->x1));
+  a->add(Object(rect->y1));
+  a->add(Object(rect->x2));
+  a->add(Object(rect->y2));
 
-  update("Rect", &obj1);
+  update("Rect", Object(a));
   invalidateAppearance();
 }
 
@@ -1423,19 +1374,17 @@
   return rect->contains(x, y);
 }
 
-void Annot::update(const char *key, Object *value) {
+void Annot::update(const char *key, Object &&value) {
   annotLocker();
   /* Set M to current time, unless we are updating M itself */
   if (strcmp(key, "M") != 0) {
     delete modified;
     modified = timeToDateString(NULL);
 
-    Object obj1;
-    obj1.initString (modified->copy());
-    annotObj.dictSet("M", &obj1);
+    annotObj.dictSet("M", Object(modified->copy()));
   }
 
-  annotObj.dictSet(const_cast<char*>(key), value);
+  annotObj.dictSet(const_cast<char*>(key), std::move(value));
   
   xref->setModifiedObject(&annotObj, ref);
 }
@@ -1455,9 +1404,7 @@
     contents = new GooString();
   }
   
-  Object obj1;
-  obj1.initString(contents->copy());
-  update ("Contents", &obj1);
+  update ("Contents", Object(contents->copy()));
 }
 
 void Annot::setName(GooString *new_name) {
@@ -1470,9 +1417,7 @@
     name = new GooString();
   }
 
-  Object obj1;
-  obj1.initString(name->copy());
-  update ("NM", &obj1);
+  update ("NM", Object(name->copy()));
 }
 
 void Annot::setModified(GooString *new_modified) {
@@ -1484,17 +1429,13 @@
   else
     modified = new GooString();
 
-  Object obj1;
-  obj1.initString(modified->copy());
-  update ("M", &obj1);
+  update ("M", Object(modified->copy()));
 }
 
 void Annot::setFlags(Guint new_flags) {
   annotLocker();
-  Object obj1;
   flags = new_flags;
-  obj1.initInt(flags);
-  update ("F", &obj1);
+  update ("F", Object(int(flags)));
 }
 
 void Annot::setBorder(AnnotBorder *new_border) {
@@ -1502,9 +1443,8 @@
   delete border;
 
   if (new_border) {
-    Object obj1;
-    new_border->writeToObject(xref, &obj1);
-    update(new_border->getType() == AnnotBorder::typeArray ? "Border" : "BS", &obj1);
+    Object obj1 = new_border->writeToObject(xref);
+    update(new_border->getType() == AnnotBorder::typeArray ? "Border" : "BS", std::move(obj1));
     border = new_border;
   } else {
     border = NULL;
@@ -1517,9 +1457,8 @@
   delete color;
 
   if (new_color) {
-    Object obj1;
-    new_color->writeToObject(xref, &obj1);
-    update ("C", &obj1);
+    Object obj1 = new_color->writeToObject(xref);
+    update ("C", std::move(obj1));
     color = new_color;
   } else {
     color = NULL;
@@ -1530,19 +1469,18 @@
 void Annot::setPage(int pageIndex, GBool updateP) {
   annotLocker();
   Page *pageobj = doc->getPage(pageIndex);
-  Object obj1;
+  Object obj1(objNull);
 
   if (pageobj) {
     Ref pageRef = pageobj->getRef();
-    obj1.initRef(pageRef.num, pageRef.gen);
+    obj1 = Object(pageRef.num, pageRef.gen);
     page = pageIndex;
   } else {
-    obj1.initNull();
     page = 0;
   }
 
   if (updateP) {
-    update("P", &obj1);
+    update("P", std::move(obj1));
   }
 }
 
@@ -1557,16 +1495,13 @@
   delete appearBBox;
   appearBBox = NULL;
 
-  Object obj1;
-  obj1.initName(state);
-  update ("AS", &obj1);
+  update ("AS", Object(objName, state));
 
   // The appearance state determines the current appearance stream
-  appearance.free();
   if (appearStreams) {
-    appearStreams->getAppearanceStream(AnnotAppearance::appearNormal, appearState->getCString(), &appearance);
+    appearance = appearStreams->getAppearanceStream(AnnotAppearance::appearNormal, appearState->getCString());
   } else {
-    appearance.initNull();
+    appearance.setToNull();
   }
 }
 
@@ -1584,18 +1519,15 @@
   delete appearBBox;
   appearBBox = NULL;
 
-  appearance.free();
-  appearance.initNull();
+  appearance.setToNull();
 
-  Object obj1, obj2;
-  obj1.initNull();
-  if (!annotObj.dictLookup("AP", &obj2)->isNull())
-    update ("AP", &obj1); // Remove AP
-  obj2.free();
+  Object obj2 = annotObj.dictLookup("AP");
+  if (!obj2.isNull())
+    update ("AP", Object(objNull)); // Remove AP
 
-  if (!annotObj.dictLookup("AS", &obj2)->isNull())
-    update ("AS", &obj1); // Remove AS
-  obj2.free();
+  obj2 = annotObj.dictLookup("AS");
+  if (!obj2.isNull())
+    update ("AS", Object(objNull)); // Remove AS
 }
 
 double Annot::getXMin() {
@@ -1615,16 +1547,13 @@
 }
 
 void Annot::readArrayNum(Object *pdfArray, int key, double *value) {
-  Object valueObject;
-
-  pdfArray->arrayGet(key, &valueObject);
+  Object valueObject = pdfArray->arrayGet(key);
   if (valueObject.isNum()) {
     *value = valueObject.getNum();
   } else {
     *value = 0;
     ok = gFalse;
   }
-  valueObject.free();
 }
 
 void Annot::removeReferencedObjects() {
@@ -1654,8 +1583,6 @@
 }
 
 Annot::~Annot() {
-  annotObj.free();
-  
   delete rect;
   delete contents;
 
@@ -1667,7 +1594,6 @@
 
   delete appearStreams;
   delete appearBBox;
-  appearance.free();
 
   if (appearState)
     delete appearState;
@@ -1678,8 +1604,6 @@
   if (color)
     delete color;
 
-  oc.free();
-
 #if MULTITHREADED
     gDestroyMutex(&mutex);
 #endif
@@ -1804,74 +1728,66 @@
   appearBuf->append("S\n");
 }
 
-void Annot::createForm(double *bbox, GBool transparencyGroup, Object *resDict, Object *aStream) {
-  Object obj1, obj2;
-  Object appearDict;
+Object Annot::createForm(double *bbox, GBool transparencyGroup, Dict *resDict) {
+  Dict *appearDict = new Dict(xref);
+  appearDict->set("Length", Object(appearBuf->getLength()));
+  appearDict->set("Subtype", Object(objName, "Form"));
 
-  appearDict.initDict(xref);
-  appearDict.dictSet("Length", obj1.initInt(appearBuf->getLength()));
-  appearDict.dictSet("Subtype", obj1.initName("Form"));
-  obj1.initArray(xref);
-  obj1.arrayAdd(obj2.initReal(bbox[0]));
-  obj1.arrayAdd(obj2.initReal(bbox[1]));
-  obj1.arrayAdd(obj2.initReal(bbox[2]));
-  obj1.arrayAdd(obj2.initReal(bbox[3]));
-  appearDict.dictSet("BBox", &obj1);
+  Array *a = new Array(xref);
+  a->add(Object(bbox[0]));
+  a->add(Object(bbox[1]));
+  a->add(Object(bbox[2]));
+  a->add(Object(bbox[3]));
+  appearDict->set("BBox", Object(a));
   if (transparencyGroup) {
-    Object transDict;
-    transDict.initDict(xref);
-    transDict.dictSet("S", obj1.initName("Transparency"));
-    appearDict.dictSet("Group", &transDict);
+    Dict *d = new Dict(xref);
+    d->set("S", Object(objName, "Transparency"));
+    appearDict->set("Group", Object(d));
   }
   if (resDict)
-    appearDict.dictSet("Resources", resDict);
+    appearDict->set("Resources", Object(resDict));
 
   MemStream *mStream = new MemStream(copyString(appearBuf->getCString()), 0,
-				     appearBuf->getLength(), &appearDict);
+				     appearBuf->getLength(), Object(appearDict));
   mStream->setNeedFree(gTrue);
-  aStream->initStream(mStream);
+  return Object(static_cast<Stream*>(mStream));
 }
 
-void Annot::createResourcesDict(const char *formName, Object *formStream,
+Dict *Annot::createResourcesDict(const char *formName, Object &&formStream,
 				const char *stateName,
-				double opacity, const char *blendMode,
-				Object *resDict) {
-  Object gsDict, stateDict, formDict, obj1;
-
-  gsDict.initDict(xref);
+				double opacity, const char *blendMode) {
+  Dict *gsDict = new Dict(xref);
   if (opacity != 1) {
-    gsDict.dictSet("CA", obj1.initReal(opacity));
-    gsDict.dictSet("ca", obj1.initReal(opacity));
+    gsDict->set("CA", Object(opacity));
+    gsDict->set("ca", Object(opacity));
   }
   if (blendMode)
-    gsDict.dictSet("BM", obj1.initName(blendMode));
-  stateDict.initDict(xref);
-  stateDict.dictSet(stateName, &gsDict);
-  formDict.initDict(xref);
-  formDict.dictSet(formName, formStream);
+    gsDict->set("BM", Object(objName, blendMode));
+  Dict *stateDict = new Dict(xref);
+  stateDict->set(stateName, Object(gsDict));
+  Dict *formDict = new Dict(xref);
+  formDict->set(formName, std::move(formStream));
 
-  resDict->initDict(xref);
-  resDict->dictSet("ExtGState", &stateDict);
-  resDict->dictSet("XObject", &formDict);
+  Dict *resDict = new Dict(xref);
+  resDict->set("ExtGState", Object(stateDict));
+  resDict->set("XObject", Object(formDict));
+
+  return resDict;
 }
 
-Object *Annot::getAppearanceResDict(Object *dest) {
+Object Annot::getAppearanceResDict() {
   Object obj1, obj2;
 
-  dest->initNull(); // Default value
-
   // Fetch appearance's resource dict (if any)
-  appearance.fetch(xref, &obj1);
+  obj1 = appearance.fetch(xref);
   if (obj1.isStream()) {
-    obj1.streamGetDict()->lookup("Resources", &obj2);
+    obj2 = obj1.streamGetDict()->lookup("Resources");
     if (obj2.isDict()) {
-      obj2.copy(dest);
+      return obj2;
     }
-    obj2.free();
   }
-  obj1.free();
 
-  return dest;
+  return Object(objNull);
 }
 
 GBool Annot::isVisible(GBool printing) {
@@ -1905,17 +1821,14 @@
 }
 
 void Annot::draw(Gfx *gfx, GBool printing) {
-  Object obj;
-
   annotLocker();
   if (!isVisible (printing))
     return;
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
       rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
-  obj.free();
 }
 
 //------------------------------------------------------------------------
@@ -1928,52 +1841,45 @@
 
   type = typePopup;
 
-  annotObj.dictSet ("Subtype", obj1.initName ("Popup"));
+  annotObj.dictSet ("Subtype", Object(objName, "Popup"));
   initialize (docA, annotObj.getDict());
 }
 
-AnnotPopup::AnnotPopup(PDFDoc *docA, Dict *dict, Object *obj) :
-    Annot(docA, dict, obj) {
+AnnotPopup::AnnotPopup(PDFDoc *docA, Object *dictObject, Object *obj) :
+    Annot(docA, dictObject, obj) {
   type = typePopup;
-  initialize(docA, dict);
+  initialize(docA, dictObject->getDict());
 }
 
 AnnotPopup::~AnnotPopup() {
-  parent.free();
 }
 
 void AnnotPopup::initialize(PDFDoc *docA, Dict *dict) {
-  Object obj1;
-
-  if (!dict->lookupNF("Parent", &parent)->isRef()) {
-    parent.initNull();
+  parent = dict->lookupNF("Parent");
+  if (!parent.isRef()) {
+    parent.setToNull();
   }
 
-  if (dict->lookup("Open", &obj1)->isBool()) {
+  Object obj1 = dict->lookup("Open");
+  if (obj1.isBool()) {
     open = obj1.getBool();
   } else {
     open = gFalse;
   }
-  obj1.free();
 }
 
 void AnnotPopup::setParent(Object *parentA) {
-  parentA->copy(&parent);
-  update ("Parent", &parent);
+  update ("Parent", parentA->copy());
 }
 
 void AnnotPopup::setParent(Annot *parentA) {
-  Ref parentRef = parentA->getRef();
-  parent.initRef(parentRef.num, parentRef.gen);
-  update ("Parent", &parent);
+  const Ref parentRef = parentA->getRef();
+  update ("Parent", Object(parentRef.num, parentRef.gen));
 }
 
 void AnnotPopup::setOpen(GBool openA) {
-  Object obj1;
-
   open = openA;
-  obj1.initBool(open);
-  update ("Open", &obj1);
+  update ("Open", Object(open));
 }
 
 //------------------------------------------------------------------------
@@ -1984,9 +1890,9 @@
   initialize(docA, annotObj.getDict(), &annotObj);
 }
 
-AnnotMarkup::AnnotMarkup(PDFDoc *docA, Dict *dict, Object *obj) :
-    Annot(docA, dict, obj) {
-  initialize(docA, dict, obj);
+AnnotMarkup::AnnotMarkup(PDFDoc *docA, Object *dictObject, Object *obj) :
+    Annot(docA, dictObject, obj) {
+  initialize(docA, dictObject->getDict(), obj);
 }
 
 AnnotMarkup::~AnnotMarkup() {
@@ -2006,50 +1912,52 @@
 void AnnotMarkup::initialize(PDFDoc *docA, Dict *dict, Object *obj) {
   Object obj1, obj2;
 
-  if (dict->lookup("T", &obj1)->isString()) {
+  obj1 = dict->lookup("T");
+  if (obj1.isString()) {
     label = obj1.getString()->copy();
   } else {
     label = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("Popup", &obj1)->isDict() && dict->lookupNF("Popup", &obj2)->isRef()) {
-    popup = new AnnotPopup(docA, obj1.getDict(), &obj2);
+  obj1 = dict->lookup("Popup");
+  obj2 = dict->lookupNF("Popup");
+  if (obj1.isDict() && obj2.isRef()) {
+    popup = new AnnotPopup(docA, &obj1, &obj2);
   } else {
     popup = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("CA", &obj1)->isNum()) {
+  obj1 = dict->lookup("CA");
+  if (obj1.isNum()) {
     opacity = obj1.getNum();
   } else {
     opacity = 1.0;
   }
-  obj1.free();
 
-  if (dict->lookup("CreationDate", &obj1)->isString()) {
+  obj1 = dict->lookup("CreationDate");
+  if (obj1.isString()) {
     date = obj1.getString()->copy();
   } else {
     date = NULL;
   }
-  obj1.free();
 
-  if (dict->lookupNF("IRT", &obj1)->isRef()) {
+  obj1 = dict->lookupNF("IRT");
+  if (obj1.isRef()) {
     inReplyTo = obj1.getRef();
   } else {
     inReplyTo.num = 0;
     inReplyTo.gen = 0;
   }
-  obj1.free();
 
-  if (dict->lookup("Subj", &obj1)->isString()) {
+  obj1 = dict->lookup("Subj");
+  if (obj1.isString()) {
     subject = obj1.getString()->copy();
   } else {
     subject = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("RT", &obj1)->isName()) {
+  obj1 = dict->lookup("RT");
+  if (obj1.isName()) {
     const char *replyName = obj1.getName();
 
     if (!strcmp(replyName, "R")) {
@@ -2062,14 +1970,13 @@
   } else {
     replyTo = replyTypeR;
   }
-  obj1.free();
 
-  if (dict->lookup("ExData", &obj1)->isDict()) {
+  obj1 = dict->lookup("ExData");
+  if (obj1.isDict()) {
     exData = parseAnnotExternalData(obj1.getDict());
   } else {
     exData = annotExternalDataMarkupUnknown;
   }
-  obj1.free();
 }
 
 void AnnotMarkup::setLabel(GooString *new_label) {
@@ -2086,9 +1993,7 @@
     label = new GooString();
   }
 
-  Object obj1;
-  obj1.initString(label->copy());
-  update ("T", &obj1);
+  update ("T", Object(label->copy()));
 }
 
 void AnnotMarkup::setPopup(AnnotPopup *new_popup) {
@@ -2105,11 +2010,8 @@
   delete popup;
 
   if (new_popup) {
-    Object obj1;
-    Ref popupRef = new_popup->getRef();
-
-    obj1.initRef (popupRef.num, popupRef.gen);
-    update ("Popup", &obj1);
+    const Ref popupRef = new_popup->getRef();
+    update ("Popup", Object(popupRef.num, popupRef.gen));
 
     new_popup->setParent(this);
     popup = new_popup;
@@ -2128,11 +2030,8 @@
 }
 
 void AnnotMarkup::setOpacity(double opacityA) {
-  Object obj1;
-
   opacity = opacityA;
-  obj1.initReal(opacity);
-  update ("CA", &obj1);
+  update ("CA", Object(opacity));
   invalidateAppearance();
 }
 
@@ -2144,9 +2043,7 @@
   else
     date = new GooString();
 
-  Object obj1;
-  obj1.initString(date->copy());
-  update ("CreationDate", &obj1);
+  update ("CreationDate", Object(date->copy()));
 }
 
 void AnnotMarkup::removeReferencedObjects() {
@@ -2167,21 +2064,19 @@
 
 AnnotText::AnnotText(PDFDoc *docA, PDFRectangle *rect) :
     AnnotMarkup(docA, rect) {
-  Object obj1;
-
   type = typeText;
   flags |= flagNoZoom | flagNoRotate;
 
-  annotObj.dictSet ("Subtype", obj1.initName ("Text"));
+  annotObj.dictSet ("Subtype", Object(objName, "Text"));
   initialize (docA, annotObj.getDict());
 }
 
-AnnotText::AnnotText(PDFDoc *docA, Dict *dict, Object *obj) :
-    AnnotMarkup(docA, dict, obj) {
+AnnotText::AnnotText(PDFDoc *docA, Object *dictObject, Object *obj) :
+    AnnotMarkup(docA, dictObject, obj) {
 
   type = typeText;
   flags |= flagNoZoom | flagNoRotate;
-  initialize (docA, dict);
+  initialize (docA, dictObject->getDict());
 }
 
 AnnotText::~AnnotText() {
@@ -2191,24 +2086,25 @@
 void AnnotText::initialize(PDFDoc *docA, Dict *dict) {
   Object obj1;
 
-  if (dict->lookup("Open", &obj1)->isBool())
+  obj1 = dict->lookup("Open");
+  if (obj1.isBool())
     open = obj1.getBool();
   else
     open = gFalse;
-  obj1.free();
 
-  if (dict->lookup("Name", &obj1)->isName()) {
+  obj1 = dict->lookup("Name");
+  if (obj1.isName()) {
     icon = new GooString(obj1.getName());
   } else {
     icon = new GooString("Note");
   }
-  obj1.free();
 
-  if (dict->lookup("StateModel", &obj1)->isString()) {
-    Object obj2;
+  obj1 = dict->lookup("StateModel");
+  if (obj1.isString()) {
     GooString *modelName = obj1.getString();
 
-    if (dict->lookup("State", &obj2)->isString()) {
+    Object obj2 = dict->lookup("State");
+    if (obj2.isString()) {
       GooString *stateName = obj2.getString();
 
       if (!stateName->cmp("Marked")) {
@@ -2231,7 +2127,6 @@
     } else {
       state = stateUnknown;
     }
-    obj2.free();
 
     if (!modelName->cmp("Marked")) {
       switch (state) {
@@ -2266,15 +2161,13 @@
   } else {
     state = stateUnknown;
   }
-  obj1.free();
 }
 
 void AnnotText::setOpen(GBool openA) {
   Object obj1;
 
   open = openA;
-  obj1.initBool(open);
-  update ("Open", &obj1);
+  update ("Open", Object(open));
 }
 
 void AnnotText::setIcon(GooString *new_icon) {
@@ -2289,9 +2182,7 @@
     icon = new GooString("Note");
   }
 
-  Object obj1;
-  obj1.initName (icon->getCString());
-  update("Name", &obj1);
+  update("Name", Object(objName, icon->getCString()));
   invalidateAppearance();
 }
 
@@ -2540,7 +2431,6 @@
   "19.5 12.5 m S\n"
 
 void AnnotText::draw(Gfx *gfx, GBool printing) {
-  Object obj;
   double ca = 1;
 
   if (!isVisible (printing))
@@ -2583,22 +2473,20 @@
     double bbox[4];
     appearBBox->getBBoxRect(bbox);
     if (ca == 1) {
-      createForm(bbox, gFalse, NULL, &appearance);
+      appearance = createForm(bbox, gFalse, nullptr);
     } else {
-      Object aStream, resDict;
-
-      createForm(bbox, gTrue, NULL, &aStream);
+      Object aStream = createForm(bbox, gTrue, nullptr);
       delete appearBuf;
 
       appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
-      createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
-      createForm(bbox, gFalse, &resDict, &appearance);
+      Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, NULL);
+      appearance = createForm(bbox, gFalse, resDict);
     }
     delete appearBuf;
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   if (appearBBox) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    appearBBox->getPageXMin(), appearBBox->getPageYMin(),
@@ -2608,7 +2496,6 @@
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   }
-  obj.free();
 }
 
 //------------------------------------------------------------------------
@@ -2619,15 +2506,15 @@
   Object obj1;
 
   type = typeLink;
-  annotObj.dictSet ("Subtype", obj1.initName ("Link"));
+  annotObj.dictSet ("Subtype", Object(objName, "Link"));
   initialize (docA, annotObj.getDict());
 }
 
-AnnotLink::AnnotLink(PDFDoc *docA, Dict *dict, Object *obj) :
-    Annot(docA, dict, obj) {
+AnnotLink::AnnotLink(PDFDoc *docA, Object *dictObject, Object *obj) :
+    Annot(docA, dictObject, obj) {
 
   type = typeLink;
-  initialize (docA, dict);
+  initialize (docA, dictObject->getDict());
 }
 
 AnnotLink::~AnnotLink() {
@@ -2646,18 +2533,19 @@
   action = NULL;
 
   // look for destination
-  if (!dict->lookup("Dest", &obj1)->isNull()) {
+  obj1 = dict->lookup("Dest");
+  if (!obj1.isNull()) {
     action = LinkAction::parseDest(&obj1);
   // look for action
   } else {
-    obj1.free();
-    if (dict->lookup("A", &obj1)->isDict()) {
+    obj1 = dict->lookup("A");
+    if (obj1.isDict()) {
       action = LinkAction::parseAction(&obj1, doc->getCatalog()->getBaseURI());
     }
   }
-  obj1.free();
 
-  if (dict->lookup("H", &obj1)->isName()) {
+  obj1 = dict->lookup("H");
+  if (obj1.isName()) {
     const char *effect = obj1.getName();
 
     if (!strcmp(effect, "N")) {
@@ -2674,43 +2562,40 @@
   } else {
     linkEffect = effectInvert;
   }
-  obj1.free();
   /*
-  if (dict->lookup("PA", &obj1)->isDict()) {
+  obj1 = dict->lookup("PA");
+  if (obj1.isDict()) {
     uriAction = NULL;
   } else {
     uriAction = NULL;
   }
   obj1.free();
   */
-  if (dict->lookup("QuadPoints", &obj1)->isArray()) {
+  obj1 = dict->lookup("QuadPoints");
+  if (obj1.isArray()) {
     quadrilaterals = new AnnotQuadrilaterals(obj1.getArray(), rect);
   } else {
     quadrilaterals = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("BS", &obj1)->isDict()) {
+  obj1 = dict->lookup("BS");
+  if (obj1.isDict()) {
     delete border;
     border = new AnnotBorderBS(obj1.getDict());
   } else if (!border) {
     border = new AnnotBorderBS();
   }
-  obj1.free();
 }
 
 void AnnotLink::draw(Gfx *gfx, GBool printing) {
-  Object obj;
-
   if (!isVisible (printing))
     return;
 
   annotLocker();
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   gfx->drawAnnot(&obj, border, color,
 		 rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
-  obj.free();
 }
 
 //------------------------------------------------------------------------
@@ -2722,19 +2607,16 @@
 
   type = typeFreeText;
 
-  annotObj.dictSet ("Subtype", obj1.initName ("FreeText"));
-
-  Object obj2;
-  obj2.initString (da->copy());
-  annotObj.dictSet("DA", &obj2);
+  annotObj.dictSet ("Subtype", Object(objName, "FreeText"));
+  annotObj.dictSet("DA", Object(da->copy()));
 
   initialize (docA, annotObj.getDict());
 }
 
-AnnotFreeText::AnnotFreeText(PDFDoc *docA, Dict *dict, Object *obj) :
-    AnnotMarkup(docA, dict, obj) {
+AnnotFreeText::AnnotFreeText(PDFDoc *docA, Object *dictObject, Object *obj) :
+    AnnotMarkup(docA, dictObject, obj) {
   type = typeFreeText;
-  initialize(docA, dict);
+  initialize(docA, dictObject->getDict());
 }
 
 AnnotFreeText::~AnnotFreeText() {
@@ -2756,48 +2638,43 @@
 void AnnotFreeText::initialize(PDFDoc *docA, Dict *dict) {
   Object obj1;
 
-  if (dict->lookup("DA", &obj1)->isString()) {
+  obj1 = dict->lookup("DA");
+  if (obj1.isString()) {
     appearanceString = obj1.getString()->copy();
   } else {
     appearanceString = new GooString();
     error(errSyntaxError, -1, "Bad appearance for annotation");
     ok = gFalse;
   }
-  obj1.free();
 
-  if (dict->lookup("Q", &obj1)->isInt()) {
+  obj1 = dict->lookup("Q");
+  if (obj1.isInt()) {
     quadding = (AnnotFreeTextQuadding) obj1.getInt();
   } else {
     quadding = quaddingLeftJustified;
   }
-  obj1.free();
 
-  if (dict->lookup("DS", &obj1)->isString()) {
+  obj1 = dict->lookup("DS");
+  if (obj1.isString()) {
     styleString = obj1.getString()->copy();
   } else {
     styleString = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("CL", &obj1)->isArray() && obj1.arrayGetLength() >= 4) {
+  obj1 = dict->lookup("CL");
+  if (obj1.isArray() && obj1.arrayGetLength() >= 4) {
     double x1, y1, x2, y2;
     Object obj2;
 
-    (obj1.arrayGet(0, &obj2)->isNum() ? x1 = obj2.getNum() : x1 = 0);
-    obj2.free();
-    (obj1.arrayGet(1, &obj2)->isNum() ? y1 = obj2.getNum() : y1 = 0);
-    obj2.free();
-    (obj1.arrayGet(2, &obj2)->isNum() ? x2 = obj2.getNum() : x2 = 0);
-    obj2.free();
-    (obj1.arrayGet(3, &obj2)->isNum() ? y2 = obj2.getNum() : y2 = 0);
-    obj2.free();
+    (obj2 = obj1.arrayGet(0), obj2.isNum() ? x1 = obj2.getNum() : x1 = 0);
+    (obj2 = obj1.arrayGet(1), obj2.isNum() ? y1 = obj2.getNum() : y1 = 0);
+    (obj2 = obj1.arrayGet(2), obj2.isNum() ? x2 = obj2.getNum() : x2 = 0);
+    (obj2 = obj1.arrayGet(3), obj2.isNum() ? y2 = obj2.getNum() : y2 = 0);
 
     if (obj1.arrayGetLength() == 6) {
       double x3, y3;
-      (obj1.arrayGet(4, &obj2)->isNum() ? x3 = obj2.getNum() : x3 = 0);
-      obj2.free();
-      (obj1.arrayGet(5, &obj2)->isNum() ? y3 = obj2.getNum() : y3 = 0);
-      obj2.free();
+      (obj2 = obj1.arrayGet(4), obj2.isNum() ? x3 = obj2.getNum() : x3 = 0);
+      (obj2 = obj1.arrayGet(5), obj2.isNum() ? y3 = obj2.getNum() : y3 = 0);
       calloutLine = new AnnotCalloutMultiLine(x1, y1, x2, y2, x3, y3);
     } else {
       calloutLine = new AnnotCalloutLine(x1, y1, x2, y2);
@@ -2805,9 +2682,9 @@
   } else {
     calloutLine = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("IT", &obj1)->isName()) {
+  obj1 = dict->lookup("IT");
+  if (obj1.isName()) {
     const char *intentName = obj1.getName();
 
     if (!strcmp(intentName, "FreeText")) {
@@ -2822,37 +2699,36 @@
   } else {
     intent = intentFreeText;
   }
-  obj1.free();
 
-  if (dict->lookup("BS", &obj1)->isDict()) {
+  obj1 = dict->lookup("BS");
+  if (obj1.isDict()) {
     delete border;
     border = new AnnotBorderBS(obj1.getDict());
   } else if (!border) {
     border = new AnnotBorderBS();
   }
-  obj1.free();
 
-  if (dict->lookup("BE", &obj1)->isDict()) {
+  obj1 = dict->lookup("BE");
+  if (obj1.isDict()) {
     borderEffect = new AnnotBorderEffect(obj1.getDict());
   } else {
     borderEffect = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("RD", &obj1)->isArray()) {
+  obj1 = dict->lookup("RD");
+  if (obj1.isArray()) {
     rectangle = parseDiffRectangle(obj1.getArray(), rect);
   } else {
     rectangle = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("LE", &obj1)->isName()) {
+  obj1 = dict->lookup("LE");
+  if (obj1.isName()) {
     GooString styleName(obj1.getName());
     endStyle = parseAnnotLineEndingStyle(&styleName);
   } else {
     endStyle = annotLineEndingNone;
   }
-  obj1.free();
 }
 
 void AnnotFreeText::setContents(GooString *new_content) {
@@ -2869,17 +2745,14 @@
     appearanceString = new GooString();
   }
 
-  Object obj1;
-  obj1.initString(appearanceString->copy());
-  update ("DA", &obj1);
+  update ("DA", Object(appearanceString->copy()));
   invalidateAppearance();
 }
 
 void AnnotFreeText::setQuadding(AnnotFreeTextQuadding new_quadding) {
   Object obj1;
   quadding = new_quadding;
-  obj1.initInt((int)quadding);
-  update ("Q", &obj1);
+  update ("Q", Object((int)quadding));
   invalidateAppearance();
 }
 
@@ -2897,9 +2770,7 @@
     styleString = new GooString();
   }
 
-  Object obj1;
-  obj1.initString(styleString->copy());
-  update ("DS", &obj1);
+  update ("DS", Object(styleString->copy()));
 }
 
 void AnnotFreeText::setCalloutLine(AnnotCalloutLine *line) {
@@ -2907,73 +2778,59 @@
 
   Object obj1;
   if (line == NULL) {
-    obj1.initNull();
+    obj1.setToNull();
     calloutLine = NULL;
   } else {
     double x1 = line->getX1(), y1 = line->getY1();
     double x2 = line->getX2(), y2 = line->getY2();
-    Object obj2;
-    obj1.initArray(xref);
-    obj1.arrayAdd( obj2.initReal(x1) );
-    obj1.arrayAdd( obj2.initReal(y1) );
-    obj1.arrayAdd( obj2.initReal(x2) );
-    obj1.arrayAdd( obj2.initReal(y2) );
+    obj1 = Object( new Array(xref) );
+    obj1.arrayAdd( Object(x1) );
+    obj1.arrayAdd( Object(y1) );
+    obj1.arrayAdd( Object(x2) );
+    obj1.arrayAdd( Object(y2) );
 
     AnnotCalloutMultiLine *mline = dynamic_cast<AnnotCalloutMultiLine*>(line);
     if (mline) {
       double x3 = mline->getX3(), y3 = mline->getY3();
-      obj1.arrayAdd( obj2.initReal(x3) );
-      obj1.arrayAdd( obj2.initReal(y3) );
+      obj1.arrayAdd( Object(x3) );
+      obj1.arrayAdd( Object(y3) );
       calloutLine = new AnnotCalloutMultiLine(x1, y1, x2, y2, x3, y3);
     } else {
       calloutLine = new AnnotCalloutLine(x1, y1, x2, y2);
     }
   }
 
-  update("CL", &obj1);
+  update("CL", std::move(obj1));
   invalidateAppearance();
 }
 
 void AnnotFreeText::setIntent(AnnotFreeTextIntent new_intent) {
-  Object obj1;
+  const char *intentName;
 
   intent = new_intent;
   if (new_intent == intentFreeText)
-    obj1.initName("FreeText");
+    intentName = "FreeText";
   else if (new_intent == intentFreeTextCallout)
-    obj1.initName("FreeTextCallout");
+    intentName = "FreeTextCallout";
   else // intentFreeTextTypeWriter
-    obj1.initName("FreeTextTypeWriter");
-  update ("IT", &obj1);
+    intentName = "FreeTextTypeWriter";
+  update ("IT", Object(objName, intentName));
 }
 
-static GfxFont * createAnnotDrawFont(XRef * xref, Object *fontResDict)
+static GfxFont * createAnnotDrawFont(XRef * xref, Dict *fontResDict)
 {
-  Ref dummyRef = { -1, -1 };
+  const Ref dummyRef = { -1, -1 };
 
-  Object baseFontObj, subtypeObj, encodingObj;
-  baseFontObj.initName("Helvetica");
-  subtypeObj.initName("Type0");
-  encodingObj.initName("WinAnsiEncoding");
-
-  Object fontDictObj;
   Dict *fontDict = new Dict(xref);
-  fontDict->decRef();
-  fontDict->add(copyString("BaseFont"), &baseFontObj);
-  fontDict->add(copyString("Subtype"), &subtypeObj);
-  fontDict->add(copyString("Encoding"), &encodingObj);
-  fontDictObj.initDict(fontDict);
+  fontDict->add(copyString("BaseFont"), Object(objName, "Helvetica"));
+  fontDict->add(copyString("Subtype"), Object(objName, "Type0"));
+  fontDict->add(copyString("Encoding"), Object(objName, "WinAnsiEncoding"));
 
-  Object fontsDictObj;
   Dict *fontsDict = new Dict(xref);
-  fontsDict->decRef();
-  fontsDict->add(copyString("AnnotDrawFont"), &fontDictObj);
-  fontsDictObj.initDict(fontsDict);
+  fontsDict->add(copyString("AnnotDrawFont"), Object(fontDict));
 
-  Dict *dict = new Dict(xref);
-  dict->add(copyString("Font"), &fontsDictObj);
+  fontResDict->add(copyString("Font"), Object(fontsDict));
 
-  fontResDict->initDict(dict);
   return GfxFont::makeFont(xref, "AnnotDrawFont", dummyRef, fontDict);
 }
 
@@ -3072,8 +2929,8 @@
   const double textwidth = width - 2*textmargin;
   appearBuf->appendf ("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re W n\n", textmargin, textwidth, height - 2*textmargin);
 
-  Object fontResDict;
-  GfxFont *font = createAnnotDrawFont(xref, &fontResDict);
+  Dict *fontResDict = new Dict(xref);
+  GfxFont *font = createAnnotDrawFont(xref, fontResDict);
 
   // Set font state
   setColor(fontcolor, gTrue);
@@ -3114,23 +2971,19 @@
   bbox[3] = rect->y2 - rect->y1;
 
   if (ca == 1) {
-    createForm(bbox, gFalse, &fontResDict, &appearance);
+    appearance = createForm(bbox, gFalse, fontResDict);
   } else {
-    Object aStream, resDict;
-
-    createForm(bbox, gTrue, &fontResDict, &aStream);
+    Object aStream = createForm(bbox, gTrue, fontResDict);
     delete appearBuf;
 
     appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
-    createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
-    createForm(bbox, gFalse, &resDict, &appearance);
+    Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, NULL);
+    appearance = createForm(bbox, gFalse, resDict);
   }
   delete appearBuf;
 }
 
 void AnnotFreeText::draw(Gfx *gfx, GBool printing) {
-  Object obj;
-
   if (!isVisible (printing))
     return;
 
@@ -3140,19 +2993,18 @@
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                  rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
-  obj.free();
 }
 
 // Before retrieving the res dict, regenerate the appearance stream if needed,
 // because AnnotFreeText::draw needs to store font info in the res dict
-Object *AnnotFreeText::getAppearanceResDict(Object *dest) {
+Object AnnotFreeText::getAppearanceResDict() {
   if (appearance.isNull()) {
     generateFreeTextAppearance();
   }
-  return Annot::getAppearanceResDict(dest);
+  return Annot::getAppearanceResDict();
 }
 
 //------------------------------------------------------------------------
@@ -3164,15 +3016,15 @@
   Object obj1;
 
   type = typeLine;
-  annotObj.dictSet ("Subtype", obj1.initName ("Line"));
+  annotObj.dictSet ("Subtype", Object(objName, "Line"));
 
   initialize (docA, annotObj.getDict());
 }
 
-AnnotLine::AnnotLine(PDFDoc *docA, Dict *dict, Object *obj) :
-    AnnotMarkup(docA, dict, obj) {
+AnnotLine::AnnotLine(PDFDoc *docA, Object *dictObject, Object *obj) :
+    AnnotMarkup(docA, dictObject, obj) {
   type = typeLine;
-  initialize(docA, dict);
+  initialize(docA, dictObject->getDict());
 }
 
 AnnotLine::~AnnotLine() {
@@ -3189,18 +3041,15 @@
 void AnnotLine::initialize(PDFDoc *docA, Dict *dict) {
   Object obj1;
 
-  if (dict->lookup("L", &obj1)->isArray() && obj1.arrayGetLength() == 4) {
+  obj1 = dict->lookup("L");
+  if (obj1.isArray() && obj1.arrayGetLength() == 4) {
     Object obj2;
     double x1, y1, x2, y2;
 
-    (obj1.arrayGet(0, &obj2)->isNum() ? x1 = obj2.getNum() : x1 = 0);
-    obj2.free();
-    (obj1.arrayGet(1, &obj2)->isNum() ? y1 = obj2.getNum() : y1 = 0);
-    obj2.free();
-    (obj1.arrayGet(2, &obj2)->isNum() ? x2 = obj2.getNum() : x2 = 0);
-    obj2.free();
-    (obj1.arrayGet(3, &obj2)->isNum() ? y2 = obj2.getNum() : y2 = 0);
-    obj2.free();
+    (obj2 = obj1.arrayGet(0), obj2.isNum() ? x1 = obj2.getNum() : x1 = 0);
+    (obj2 = obj1.arrayGet(1), obj2.isNum() ? y1 = obj2.getNum() : y1 = 0);
+    (obj2 = obj1.arrayGet(2), obj2.isNum() ? x2 = obj2.getNum() : x2 = 0);
+    (obj2 = obj1.arrayGet(3), obj2.isNum() ? y2 = obj2.getNum() : y2 = 0);
 
     coord1 = new AnnotCoord(x1, y1);
     coord2 = new AnnotCoord(x2, y2);
@@ -3208,43 +3057,43 @@
     coord1 = new AnnotCoord();
     coord2 = new AnnotCoord();
   }
-  obj1.free();
 
-  if (dict->lookup("LE", &obj1)->isArray() && obj1.arrayGetLength() == 2) {
+  obj1 = dict->lookup("LE");
+  if (obj1.isArray() && obj1.arrayGetLength() == 2) {
     Object obj2;
 
-    if(obj1.arrayGet(0, &obj2)->isString())
+    obj2 = obj1.arrayGet(0);
+    if (obj2.isString())
       startStyle = parseAnnotLineEndingStyle(obj2.getString());
     else
       startStyle = annotLineEndingNone;
-    obj2.free();
 
-    if(obj1.arrayGet(1, &obj2)->isString())
+    obj2 = obj1.arrayGet(1);
+    if (obj2.isString())
       endStyle = parseAnnotLineEndingStyle(obj2.getString());
     else
       endStyle = annotLineEndingNone;
-    obj2.free();
 
   } else {
     startStyle = endStyle = annotLineEndingNone;
   }
-  obj1.free();
 
-  if (dict->lookup("IC", &obj1)->isArray()) {
+  obj1 = dict->lookup("IC");
+  if (obj1.isArray()) {
     interiorColor = new AnnotColor(obj1.getArray());
   } else {
     interiorColor = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("LL", &obj1)->isNum()) {
+  obj1 = dict->lookup("LL");
+  if (obj1.isNum()) {
     leaderLineLength = obj1.getNum();
   } else {
     leaderLineLength = 0;
   }
-  obj1.free();
 
-  if (dict->lookup("LLE", &obj1)->isNum()) {
+  obj1 = dict->lookup("LLE");
+  if (obj1.isNum()) {
     leaderLineExtension = obj1.getNum();
 
     if (leaderLineExtension < 0)
@@ -3252,16 +3101,16 @@
   } else {
     leaderLineExtension = 0;
   }
-  obj1.free();
 
-  if (dict->lookup("Cap", &obj1)->isBool()) {
+  obj1 = dict->lookup("Cap");
+  if (obj1.isBool()) {
     caption = obj1.getBool();
   } else {
     caption = gFalse;
   }
-  obj1.free();
 
-  if (dict->lookup("IT", &obj1)->isName()) {
+  obj1 = dict->lookup("IT");
+  if (obj1.isName()) {
     const char *intentName = obj1.getName();
 
     if(!strcmp(intentName, "LineArrow")) {
@@ -3274,9 +3123,9 @@
   } else {
     intent = intentLineArrow;
   }
-  obj1.free();
 
-  if (dict->lookup("LLO", &obj1)->isNum()) {
+  obj1 = dict->lookup("LLO");
+  if (obj1.isNum()) {
     leaderLineOffset = obj1.getNum();
 
     if (leaderLineOffset < 0)
@@ -3284,9 +3133,9 @@
   } else {
     leaderLineOffset = 0;
   }
-  obj1.free();
 
-  if (dict->lookup("CP", &obj1)->isName()) {
+  obj1 = dict->lookup("CP");
+  if (obj1.isName()) {
     const char *captionName = obj1.getName();
 
     if(!strcmp(captionName, "Inline")) {
@@ -3299,36 +3148,33 @@
   } else {
     captionPos = captionPosInline;
   }
-  obj1.free();
 
-  if (dict->lookup("Measure", &obj1)->isDict()) {
+  obj1 = dict->lookup("Measure");
+  if (obj1.isDict()) {
     measure = NULL;
   } else {
     measure = NULL;
   }
-  obj1.free();
 
-  if ((dict->lookup("CO", &obj1)->isArray()) && (obj1.arrayGetLength() == 2)) {
+  obj1 = dict->lookup("CO");
+  if (obj1.isArray() && (obj1.arrayGetLength() == 2)) {
     Object obj2;
 
-    (obj1.arrayGet(0, &obj2)->isNum() ? captionTextHorizontal = obj2.getNum() :
-      captionTextHorizontal = 0);
-    obj2.free();
-    (obj1.arrayGet(1, &obj2)->isNum() ? captionTextVertical = obj2.getNum() :
-      captionTextVertical = 0);
-    obj2.free();
+    obj2 = obj1.arrayGet(0);
+    captionTextHorizontal = obj2.isNum() ? obj2.getNum() : 0;
+    obj2 = obj1.arrayGet(1);
+    captionTextVertical = obj2.isNum() ? obj2.getNum() : 0;
   } else {
     captionTextHorizontal = captionTextVertical = 0;
   }
-  obj1.free();
 
-  if (dict->lookup("BS", &obj1)->isDict()) {
+  obj1 = dict->lookup("BS");
+  if (obj1.isDict()) {
     delete border;
     border = new AnnotBorderBS(obj1.getDict());
   } else if (!border) {
     border = new AnnotBorderBS();
   }
-  obj1.free();
 }
 
 void AnnotLine::setContents(GooString *new_content) {
@@ -3338,34 +3184,30 @@
 }
 
 void AnnotLine::setVertices(double x1, double y1, double x2, double y2) {
-  Object obj1, obj2;
-
   delete coord1;
   coord1 = new AnnotCoord(x1, y1);
   delete coord2;
   coord2 = new AnnotCoord(x2, y2);
 
-  obj1.initArray(xref);
-  obj1.arrayAdd( obj2.initReal(x1) );
-  obj1.arrayAdd( obj2.initReal(y1) );
-  obj1.arrayAdd( obj2.initReal(x2) );
-  obj1.arrayAdd( obj2.initReal(y2) );
+  Array *lArray = new Array(xref);
+  lArray->add( Object(x1) );
+  lArray->add( Object(y1) );
+  lArray->add( Object(x2) );
+  lArray->add( Object(y2) );
 
-  update("L", &obj1);
+  update("L", Object(lArray));
   invalidateAppearance();
 }
 
 void AnnotLine::setStartEndStyle(AnnotLineEndingStyle start, AnnotLineEndingStyle end) {
-  Object obj1, obj2;
-
   startStyle = start;
   endStyle = end;
 
-  obj1.initArray(xref);
-  obj1.arrayAdd( obj2.initName(convertAnnotLineEndingStyle( startStyle )) );
-  obj1.arrayAdd( obj2.initName(convertAnnotLineEndingStyle( endStyle )) );
+  Array *leArray = new Array(xref);
+  leArray->add( Object(objName, convertAnnotLineEndingStyle( startStyle )) );
+  leArray->add( Object(objName, convertAnnotLineEndingStyle( endStyle )) );
 
-  update("LE", &obj1);
+  update("LE", Object(leArray));
   invalidateAppearance();
 }
 
@@ -3373,9 +3215,8 @@
   delete interiorColor;
 
   if (new_color) {
-    Object obj1;
-    new_color->writeToObject(xref, &obj1);
-    update ("IC", &obj1);
+    Object obj1 = new_color->writeToObject(xref);
+    update ("IC", std::move(obj1));
     interiorColor = new_color;
   } else {
     interiorColor = NULL;
@@ -3384,45 +3225,35 @@
 }
 
 void AnnotLine::setLeaderLineLength(double len) {
-  Object obj1;
-
   leaderLineLength = len;
-  obj1.initReal(len);
-  update ("LL", &obj1);
+  update ("LL", Object(len));
   invalidateAppearance();
 }
 
 void AnnotLine::setLeaderLineExtension(double len) {
-  Object obj1;
-
   leaderLineExtension = len;
-  obj1.initReal(len);
-  update ("LLE", &obj1);
+  update ("LLE", Object(len));
 
   // LL is required if LLE is present
-  obj1.initReal(leaderLineLength);
-  update ("LL", &obj1);
+  update ("LL", Object(leaderLineLength));
   invalidateAppearance();
 }
 
 void AnnotLine::setCaption(bool new_cap) {
-  Object obj1;
-
   caption = new_cap;
-  obj1.initBool(new_cap);
-  update ("Cap", &obj1);
+  update ("Cap", Object(new_cap));
   invalidateAppearance();
 }
 
 void AnnotLine::setIntent(AnnotLineIntent new_intent) {
-  Object obj1;
+  const char *intentName;
 
   intent = new_intent;
   if (new_intent == intentLineArrow)
-    obj1.initName("LineArrow");
+    intentName = "LineArrow";
   else // intentLineDimension
-    obj1.initName("LineDimension");
-  update ("IT", &obj1);
+    intentName = "LineDimension";
+  update ("IT", Object(objName, intentName));
 }
 
 void AnnotLine::generateLineAppearance()
@@ -3463,12 +3294,13 @@
   const double captionhmargin = 2; // Left and right margin (inline caption only)
   const double captionmaxwidth = main_len - 2 * captionhmargin;
 
-  Object fontResDict;
+  Dict *fontResDict;
   GfxFont *font;
 
   // Calculate caption width and height
   if (caption) {
-    font = createAnnotDrawFont(xref, &fontResDict);
+    fontResDict = new Dict(xref);
+    font = createAnnotDrawFont(xref, fontResDict);
     int lines = 0;
     int i = 0;
     while (i < contents->getLength()) {
@@ -3487,7 +3319,7 @@
       actualCaptionPos = captionPosTop;
     }
   } else {
-    fontResDict.initNull();
+    fontResDict = nullptr;
     font = NULL;
   }
 
@@ -3579,23 +3411,19 @@
   double bbox[4];
   appearBBox->getBBoxRect(bbox);
   if (ca == 1) {
-    createForm(bbox, gFalse, &fontResDict, &appearance);
+    appearance = createForm(bbox, gFalse, fontResDict);
   } else {
-    Object aStream, resDict;
-
-    createForm(bbox, gTrue, &fontResDict, &aStream);
+    Object aStream = createForm(bbox, gTrue, fontResDict);
     delete appearBuf;
 
     appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
-    createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
-    createForm(bbox, gFalse, &resDict, &appearance);
+    Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, NULL);
+    appearance = createForm(bbox, gFalse, resDict);
   }
   delete appearBuf;
 }
 
 void AnnotLine::draw(Gfx *gfx, GBool printing) {
-  Object obj;
-
   if (!isVisible (printing))
     return;
 
@@ -3605,7 +3433,7 @@
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   if (appearBBox) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    appearBBox->getPageXMin(), appearBBox->getPageYMin(),
@@ -3615,16 +3443,15 @@
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   }
-  obj.free();
 }
 
 // Before retrieving the res dict, regenerate the appearance stream if needed,
 // because AnnotLine::draw may need to store font info in the res dict
-Object *AnnotLine::getAppearanceResDict(Object *dest) {
+Object AnnotLine::getAppearanceResDict() {
   if (appearance.isNull()) {
     generateLineAppearance();
   }
-  return Annot::getAppearanceResDict(dest);
+  return Annot::getAppearanceResDict();
 }
 
 //------------------------------------------------------------------------
@@ -3636,43 +3463,43 @@
 
   switch (subType) {
     case typeHighlight:
-      annotObj.dictSet ("Subtype", obj1.initName ("Highlight"));
+      annotObj.dictSet ("Subtype", Object(objName, "Highlight"));
       break;
     case typeUnderline:
-      annotObj.dictSet ("Subtype", obj1.initName ("Underline"));
+      annotObj.dictSet ("Subtype", Object(objName, "Underline"));
       break;
     case typeSquiggly:
-      annotObj.dictSet ("Subtype", obj1.initName ("Squiggly"));
+      annotObj.dictSet ("Subtype", Object(objName, "Squiggly"));
       break;
     case typeStrikeOut:
-      annotObj.dictSet ("Subtype", obj1.initName ("StrikeOut"));
+      annotObj.dictSet ("Subtype", Object(objName, "StrikeOut"));
       break;
     default:
       assert (0 && "Invalid subtype for AnnotTextMarkup\n");
   }
 
   // Store dummy quadrilateral with null coordinates
-  Object obj2, obj3;
-  obj2.initArray (doc->getXRef());
+  Array *quadPoints = new Array(doc->getXRef());
   for (int i = 0; i < 4*2; ++i) {
-    obj2.arrayAdd (obj3.initReal (0));
+    quadPoints->add(Object(0.));
   }
-  annotObj.dictSet ("QuadPoints", &obj2);
+  annotObj.dictSet ("QuadPoints", Object(quadPoints));
 
   initialize(docA, annotObj.getDict());
 }
 
-AnnotTextMarkup::AnnotTextMarkup(PDFDoc *docA, Dict *dict, Object *obj) :
-  AnnotMarkup(docA, dict, obj) {
+AnnotTextMarkup::AnnotTextMarkup(PDFDoc *docA, Object *dictObject, Object *obj) :
+  AnnotMarkup(docA, dictObject, obj) {
   // the real type will be read in initialize()
   type = typeHighlight;
-  initialize(docA, dict);
+  initialize(docA, dictObject->getDict());
 }
 
 void AnnotTextMarkup::initialize(PDFDoc *docA, Dict *dict) {
   Object obj1;
 
-  if (dict->lookup("Subtype", &obj1)->isName()) {
+  obj1 = dict->lookup("Subtype");
+  if (obj1.isName()) {
     GooString typeName(obj1.getName());
     if (!typeName.cmp("Highlight")) {
       type = typeHighlight;
@@ -3684,76 +3511,70 @@
       type = typeStrikeOut;
     }
   }
-  obj1.free();
 
-  if(dict->lookup("QuadPoints", &obj1)->isArray()) {
+  obj1 = dict->lookup("QuadPoints");
+  if (obj1.isArray()) {
     quadrilaterals = new AnnotQuadrilaterals(obj1.getArray(), rect);
   } else {
     error(errSyntaxError, -1, "Bad Annot Text Markup QuadPoints");
     quadrilaterals = NULL;
     ok = gFalse;
   }
-  obj1.free();
 }
 
 AnnotTextMarkup::~AnnotTextMarkup() {
-  if(quadrilaterals) {
-    delete quadrilaterals;
-  }
+  delete quadrilaterals;
 }
 
 void AnnotTextMarkup::setType(AnnotSubtype new_type) {
-  Object obj1;
+  const char *typeName;
 
   switch (new_type) {
     case typeHighlight:
-      obj1.initName("Highlight");
+      typeName = "Highlight";
       break;
     case typeUnderline:
-      obj1.initName("Underline");
+      typeName = "Underline";
       break;
     case typeSquiggly:
-      obj1.initName("Squiggly");
+      typeName = "Squiggly";
       break;
     case typeStrikeOut:
-      obj1.initName("StrikeOut");
+      typeName = "StrikeOut";
       break;
     default:
       assert(!"Invalid subtype");
   }
 
   type = new_type;
-  update("Subtype", &obj1);
+  update("Subtype", Object(objName, typeName));
   invalidateAppearance();
 }
 
 void AnnotTextMarkup::setQuadrilaterals(AnnotQuadrilaterals *quadPoints) {
-  Object obj1, obj2;
-  obj1.initArray (xref);
+  Array *a = new Array(xref);
 
   for (int i = 0; i < quadPoints->getQuadrilateralsLength(); ++i) {
-    obj1.arrayAdd (obj2.initReal (quadPoints->getX1(i)));
-    obj1.arrayAdd (obj2.initReal (quadPoints->getY1(i)));
-    obj1.arrayAdd (obj2.initReal (quadPoints->getX2(i)));
-    obj1.arrayAdd (obj2.initReal (quadPoints->getY2(i)));
-    obj1.arrayAdd (obj2.initReal (quadPoints->getX3(i)));
-    obj1.arrayAdd (obj2.initReal (quadPoints->getY3(i)));
-    obj1.arrayAdd (obj2.initReal (quadPoints->getX4(i)));
-    obj1.arrayAdd (obj2.initReal (quadPoints->getY4(i)));
+    a->add(Object(quadPoints->getX1(i)));
+    a->add(Object(quadPoints->getY1(i)));
+    a->add(Object(quadPoints->getX2(i)));
+    a->add(Object(quadPoints->getY2(i)));
+    a->add(Object(quadPoints->getX3(i)));
+    a->add(Object(quadPoints->getY3(i)));
+    a->add(Object(quadPoints->getX4(i)));
+    a->add(Object(quadPoints->getY4(i)));
   }
 
   delete quadrilaterals;
-  quadrilaterals = new AnnotQuadrilaterals(obj1.getArray(), rect);
+  quadrilaterals = new AnnotQuadrilaterals(a, rect);
 
-  annotObj.dictSet ("QuadPoints", &obj1);
+  annotObj.dictSet ("QuadPoints", Object(a));
   invalidateAppearance();
 }
 
 void AnnotTextMarkup::draw(Gfx *gfx, GBool printing) {
-  Object obj;
   double ca = 1;
   int i;
-  Object obj1, obj2;
 
   if (!isVisible (printing))
     return;
@@ -3850,8 +3671,6 @@
       break;
     default:
     case typeHighlight:
-      appearance.free();
-
       if (color)
         setColor(color, gTrue);
 
@@ -3887,32 +3706,32 @@
     }
     appearBuf->append ("Q\n");
 
-    Object aStream, resDict;
+    Object aStream;
     double bbox[4];
     bbox[0] = appearBBox->getPageXMin();
     bbox[1] = appearBBox->getPageYMin();
     bbox[2] = appearBBox->getPageXMax();
     bbox[3] = appearBBox->getPageYMax();
-    createForm(bbox, gTrue, NULL, &aStream);
+    aStream = createForm(bbox, gTrue, NULL);
     delete appearBuf;
 
     appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
-    createResourcesDict("Fm0", &aStream, "GS0", 1, blendMultiply ? "Multiply" : NULL, &resDict);
+    Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", 1, blendMultiply ? "Multiply" : NULL);
     if (ca == 1) {
-      createForm(bbox, gFalse, &resDict, &appearance);
+      appearance = createForm(bbox, gFalse, resDict);
     } else {
-      createForm(bbox, gTrue, &resDict, &aStream);
+      aStream = createForm(bbox, gTrue, resDict);
       delete appearBuf;
 
       appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
-      createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
-      createForm(bbox, gFalse, &resDict, &appearance);
+      Dict *resDict2 = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, NULL);
+      appearance = createForm(bbox, gFalse, resDict2);
     }
     delete appearBuf;
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   if (appearBBox) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    appearBBox->getPageXMin(), appearBBox->getPageYMin(),
@@ -3922,25 +3741,24 @@
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   }
-  obj.free();
 }
 
 //------------------------------------------------------------------------
 // AnnotWidget
 //------------------------------------------------------------------------
 
-AnnotWidget::AnnotWidget(PDFDoc *docA, Dict *dict, Object *obj) :
-    Annot(docA, dict, obj) {
+AnnotWidget::AnnotWidget(PDFDoc *docA, Object *dictObject, Object *obj) :
+    Annot(docA, dictObject, obj) {
   type = typeWidget;
   field = NULL;
-  initialize(docA, dict);
+  initialize(docA, dictObject->getDict());
 }
 
-AnnotWidget::AnnotWidget(PDFDoc *docA, Dict *dict, Object *obj, FormField *fieldA) :
-    Annot(docA, dict, obj) {
+AnnotWidget::AnnotWidget(PDFDoc *docA, Object *dictObject, Object *obj, FormField *fieldA) :
+    Annot(docA, dictObject, obj) {
   type = typeWidget;
   field = fieldA;
-  initialize(docA, dict);
+  initialize(docA, dictObject->getDict());
 }
 
 AnnotWidget::~AnnotWidget() {
@@ -3950,8 +3768,6 @@
   if (action)
     delete action;
 
-  additionalActions.free();
-
   if (parent)
     delete parent;
 }
@@ -3961,7 +3777,8 @@
 
   form = doc->getCatalog()->getForm();
 
-  if(dict->lookup("H", &obj1)->isName()) {
+  obj1 = dict->lookup("H");
+  if (obj1.isName()) {
     const char *modeName = obj1.getName();
 
     if(!strcmp(modeName, "N")) {
@@ -3976,35 +3793,34 @@
   } else {
     mode = highlightModeInvert;
   }
-  obj1.free();
 
-  if(dict->lookup("MK", &obj1)->isDict()) {
+  obj1 = dict->lookup("MK");
+  if (obj1.isDict()) {
     appearCharacs = new AnnotAppearanceCharacs(obj1.getDict());
   } else {
     appearCharacs = NULL;
   }
-  obj1.free();
 
   action = NULL;
-  if(dict->lookup("A", &obj1)->isDict()) {
+  obj1 = dict->lookup("A");
+  if (obj1.isDict()) {
     action = LinkAction::parseAction(&obj1, doc->getCatalog()->getBaseURI());
   }
-  obj1.free();
 
-  dict->lookupNF("AA", &additionalActions);
+  additionalActions = dict->lookupNF("AA");
 
-  if(dict->lookup("Parent", &obj1)->isDict()) {
+  obj1 = dict->lookup("Parent");
+  if (obj1.isDict()) {
     parent = NULL;
   } else {
     parent = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("BS", &obj1)->isDict()) {
+  obj1 = dict->lookup("BS");
+  if (obj1.isDict()) {
     delete border;
     border = new AnnotBorderBS(obj1.getDict());
   }
-  obj1.free();
 
   updatedAppearanceStream.num = updatedAppearanceStream.gen = -1;
 }
@@ -5037,9 +4853,7 @@
 }
 
 void AnnotWidget::generateFieldAppearance() {
-  Object appearDict, obj1, obj2;
   GfxResources *resources;
-  MemStream *appearStream;
   GooString *da;
 
   appearBuf = new GooString ();
@@ -5084,28 +4898,26 @@
   }
 
   // build the appearance stream dictionary
-  appearDict.initDict(xref);
-  appearDict.dictAdd(copyString("Length"),
-      obj1.initInt(appearBuf->getLength()));
-  appearDict.dictAdd(copyString("Subtype"), obj1.initName("Form"));
-  obj1.initArray(xref);
-  obj1.arrayAdd(obj2.initReal(0));
-  obj1.arrayAdd(obj2.initReal(0));
-  obj1.arrayAdd(obj2.initReal(rect->x2 - rect->x1));
-  obj1.arrayAdd(obj2.initReal(rect->y2 - rect->y1));
-  appearDict.dictAdd(copyString("BBox"), &obj1);
+  Dict *appearDict = new Dict(xref);
+  appearDict->add(copyString("Length"), Object(appearBuf->getLength()));
+  appearDict->add(copyString("Subtype"), Object(objName, "Form"));
+  Array *bbox = new Array(xref);
+  bbox->add(Object(0));
+  bbox->add(Object(0));
+  bbox->add(Object(rect->x2 - rect->x1));
+  bbox->add(Object(rect->y2 - rect->y1));
+  appearDict->add(copyString("BBox"), Object(bbox));
 
   // set the resource dictionary
   Object *resDict = form->getDefaultResourcesObj();
   if (resDict->isDict()) {
-    appearDict.dictAdd(copyString("Resources"), resDict->copy(&obj1));
+    appearDict->add(copyString("Resources"), resDict->copy());
   }
 
   // build the appearance stream
-  appearStream = new MemStream(copyString(appearBuf->getCString()), 0,
-      appearBuf->getLength(), &appearDict);
-  appearance.free();
-  appearance.initStream(appearStream);
+  MemStream *appearStream = new MemStream(copyString(appearBuf->getCString()), 0,
+      appearBuf->getLength(), Object(appearDict));
+  appearance = Object(static_cast<Stream*>(appearStream));
   delete appearBuf;
 
   appearStream->setNeedFree(gTrue);
@@ -5128,8 +4940,7 @@
   generateFieldAppearance();
 
   // Fetch the appearance stream we've just created
-  Object obj1;
-  appearance.fetch(xref, &obj1);
+  Object obj1 = appearance.fetch(xref);
 
   // If this the first time updateAppearanceStream() is called on this widget,
   // create a new AP dictionary containing the new appearance stream.
@@ -5137,26 +4948,22 @@
   if (updatedAppearanceStream.num == -1) {
     // Write the appearance stream
     updatedAppearanceStream = xref->addIndirectObject(&obj1);
-    obj1.free();
 
     // Write the AP dictionary
-    Object obj2;
-    obj1.initDict(xref);
-    obj1.dictAdd(copyString("N"), obj2.initRef(updatedAppearanceStream.num, updatedAppearanceStream.gen));
-    update("AP", &obj1);
+    obj1 = Object(new Dict(xref));
+    obj1.dictAdd(copyString("N"), Object(updatedAppearanceStream.num, updatedAppearanceStream.gen));
 
     // Update our internal pointers to the appearance dictionary
     appearStreams = new AnnotAppearance(doc, &obj1);
+
+    update("AP", std::move(obj1));
   } else {
     // Replace the existing appearance stream
     xref->setModifiedObject(&obj1, updatedAppearanceStream);
-    obj1.free();
   }
 }
 
 void AnnotWidget::draw(Gfx *gfx, GBool printing) {
-  Object obj;
-
   if (!isVisible (printing))
     return;
 
@@ -5172,29 +4979,19 @@
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   if (addDingbatsResource) {
     // We are forcing ZaDb but the font does not exist
     // so create a fake one
-    Object baseFontObj, subtypeObj;
-    baseFontObj.initName("ZapfDingbats");
-    subtypeObj.initName("Type1");
-
-    Object fontDictObj;
     Dict *fontDict = new Dict(gfx->getXRef());
-    fontDict->decRef();
-    fontDict->add(copyString("BaseFont"), &baseFontObj);
-    fontDict->add(copyString("Subtype"), &subtypeObj);
-    fontDictObj.initDict(fontDict);
+    fontDict->add(copyString("BaseFont"), Object(objName, "ZapfDingbats"));
+    fontDict->add(copyString("Subtype"), Object(objName, "Type1"));
 
-    Object fontsDictObj;
     Dict *fontsDict = new Dict(gfx->getXRef());
-    fontsDict->decRef();
-    fontsDict->add(copyString("ZaDb"), &fontDictObj);
-    fontsDictObj.initDict(fontsDict);
+    fontsDict->add(copyString("ZaDb"), Object(fontDict));
 
     Dict *dict = new Dict(gfx->getXRef());
-    dict->add(copyString("Font"), &fontsDictObj);
+    dict->add(copyString("Font"), Object(fontsDict));
     gfx->pushResources(dict);
     delete dict;
   }
@@ -5203,7 +5000,6 @@
   if (addDingbatsResource) {
     gfx->popResources();
   }
-  obj.free();
 }
 
 
@@ -5215,7 +5011,7 @@
   Object obj1;
 
   type = typeMovie;
-  annotObj.dictSet ("Subtype", obj1.initName ("Movie"));
+  annotObj.dictSet ("Subtype", Object(objName, "Movie"));
 
   movie = movieA->copy();
   // TODO: create movie dict from movieA
@@ -5223,10 +5019,10 @@
   initialize(docA, annotObj.getDict());
 }
 
-AnnotMovie::AnnotMovie(PDFDoc *docA, Dict *dict, Object *obj) :
-  Annot(docA, dict, obj) {
+AnnotMovie::AnnotMovie(PDFDoc *docA, Object *dictObject, Object *obj) :
+  Annot(docA, dictObject, obj) {
   type = typeMovie;
-  initialize(docA, dict);
+  initialize(docA, dictObject->getDict());
 }
 
 AnnotMovie::~AnnotMovie() {
@@ -5238,17 +5034,16 @@
 void AnnotMovie::initialize(PDFDoc *docA, Dict* dict) {
   Object obj1;
 
-  if (dict->lookup("T", &obj1)->isString()) {
+  obj1 = dict->lookup("T");
+  if (obj1.isString()) {
     title = obj1.getString()->copy();
   } else {
     title = NULL;
   }
-  obj1.free();
 
-  Object movieDict;
-  if (dict->lookup("Movie", &movieDict)->isDict()) {
-    Object obj2;
-    dict->lookup("A", &obj2);
+  Object movieDict = dict->lookup("Movie");
+  if (movieDict.isDict()) {
+    Object obj2 = dict->lookup("A");
     if (obj2.isDict())
       movie = new Movie (&movieDict, &obj2);
     else
@@ -5258,79 +5053,66 @@
       movie = NULL;
       ok = gFalse;
     }
-    obj2.free();
   } else {
     error(errSyntaxError, -1, "Bad Annot Movie");
     movie = NULL;
     ok = gFalse;
   }
-  movieDict.free();
 }
 
 void AnnotMovie::draw(Gfx *gfx, GBool printing) {
-  Object obj;
-
   if (!isVisible (printing))
     return;
 
   annotLocker();
   if (appearance.isNull() && movie->getShowPoster()) {
     int width, height;
-    Object poster;
-    movie->getPoster(&poster);
+    Object poster = movie->getPoster();
     movie->getAspect(&width, &height);
 
     if (width != -1 && height != -1 && !poster.isNone()) {
-      MemStream *mStream;
-
       appearBuf = new GooString ();
       appearBuf->append ("q\n");
       appearBuf->appendf ("{0:d} 0 0 {1:d} 0 0 cm\n", width, height);
       appearBuf->append ("/MImg Do\n");
       appearBuf->append ("Q\n");
 
-      Object imgDict;
-      imgDict.initDict(gfx->getXRef());
-      imgDict.dictSet ("MImg", &poster);
+      Dict *imgDict = new Dict(gfx->getXRef());
+      imgDict->set("MImg", std::move(poster));
 
-      Object resDict;
-      resDict.initDict(gfx->getXRef());
-      resDict.dictSet ("XObject", &imgDict);
+      Dict *resDict = new Dict(gfx->getXRef());
+      resDict->set("XObject", Object(imgDict));
 
-      Object formDict, obj1, obj2;
-      formDict.initDict(gfx->getXRef());
-      formDict.dictSet("Length", obj1.initInt(appearBuf->getLength()));
-      formDict.dictSet("Subtype", obj1.initName("Form"));
-      formDict.dictSet("Name", obj1.initName("FRM"));
-      obj1.initArray(gfx->getXRef());
-      obj1.arrayAdd(obj2.initInt(0));
-      obj1.arrayAdd(obj2.initInt(0));
-      obj1.arrayAdd(obj2.initInt(width));
-      obj1.arrayAdd(obj2.initInt(height));
-      formDict.dictSet("BBox", &obj1);
-      obj1.initArray(gfx->getXRef());
-      obj1.arrayAdd(obj2.initInt(1));
-      obj1.arrayAdd(obj2.initInt(0));
-      obj1.arrayAdd(obj2.initInt(0));
-      obj1.arrayAdd(obj2.initInt(1));
-      obj1.arrayAdd(obj2.initInt(-width / 2));
-      obj1.arrayAdd(obj2.initInt(-height / 2));
-      formDict.dictSet("Matrix", &obj1);
-      formDict.dictSet("Resources", &resDict);
+      Dict *formDict = new Dict(gfx->getXRef());
+      formDict->set("Length", Object(appearBuf->getLength()));
+      formDict->set("Subtype", Object(objName, "Form"));
+      formDict->set("Name", Object(objName, "FRM"));
+      Array *bboxArray = new Array(gfx->getXRef());
+      bboxArray->add(Object(0));
+      bboxArray->add(Object(0));
+      bboxArray->add(Object(width));
+      bboxArray->add(Object(height));
+      formDict->set("BBox", Object(bboxArray));
+      Array *matrix = new Array(gfx->getXRef());
+      matrix->add(Object(1));
+      matrix->add(Object(0));
+      matrix->add(Object(0));
+      matrix->add(Object(1));
+      matrix->add(Object(-width / 2));
+      matrix->add(Object(-height / 2));
+      formDict->set("Matrix", Object(matrix));
+      formDict->set("Resources", Object(resDict));
 
-      Object aStream;
-      mStream = new MemStream(copyString(appearBuf->getCString()), 0,
-			      appearBuf->getLength(), &formDict);
+      MemStream *mStream = new MemStream(copyString(appearBuf->getCString()), 0,
+			      appearBuf->getLength(), Object(formDict));
       mStream->setNeedFree(gTrue);
-      aStream.initStream(mStream);
       delete appearBuf;
 
-      Object objDict;
-      objDict.initDict(gfx->getXRef());
-      objDict.dictSet ("FRM", &aStream);
+      Dict *dict = new Dict(gfx->getXRef());
+      dict->set("FRM", Object(static_cast<Stream*>(mStream)));
 
-      resDict.initDict(gfx->getXRef());
-      resDict.dictSet ("XObject", &objDict);
+      Dict *resDict2 = new Dict(gfx->getXRef());
+      resDict2->set("XObject", Object(dict));
 
       appearBuf = new GooString ();
       appearBuf->append ("q\n");
@@ -5346,17 +5128,15 @@
       bbox[0] = bbox[1] = 0;
       bbox[2] = width;
       bbox[3] = height;
-      createForm(bbox, gFalse, &resDict, &appearance);
+      appearance = createForm(bbox, gFalse, resDict2);
       delete appearBuf;
     }
-    poster.free();
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
 		 rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
-  obj.free();
 }
 
 //------------------------------------------------------------------------
@@ -5368,38 +5148,34 @@
 
   type = typeScreen;
 
-  annotObj.dictSet ("Subtype", obj1.initName ("Screen"));
+  annotObj.dictSet ("Subtype", Object(objName, "Screen"));
   initialize(docA, annotObj.getDict());
 }
 
-AnnotScreen::AnnotScreen(PDFDoc *docA, Dict *dict, Object *obj) :
-  Annot(docA, dict, obj) {
+AnnotScreen::AnnotScreen(PDFDoc *docA, Object *dictObject, Object *obj) :
+  Annot(docA, dictObject, obj) {
   type = typeScreen;
-  initialize(docA, dict);
+  initialize(docA, dictObject->getDict());
 }
 
 AnnotScreen::~AnnotScreen() {
-  if (title)
-    delete title;
-  if (appearCharacs)
-    delete appearCharacs;
-  if (action)
-    delete action;
-
-  additionalActions.free();
+  delete title;
+  delete appearCharacs;
+  delete action;
 }
 
 void AnnotScreen::initialize(PDFDoc *docA, Dict* dict) {
   Object obj1;
 
   title = NULL;
-  if (dict->lookup("T", &obj1)->isString()) {
+  obj1 = dict->lookup("T");
+  if (obj1.isString()) {
     title = obj1.getString()->copy();
   }
-  obj1.free();
 
   action = NULL;
-  if (dict->lookup("A", &obj1)->isDict()) {
+  obj1 = dict->lookup("A");
+  if (obj1.isDict()) {
     action = LinkAction::parseAction(&obj1, doc->getCatalog()->getBaseURI());
     if (action && action->getKind() == actionRendition && page == 0) {
       error (errSyntaxError, -1, "Invalid Rendition action: associated screen annotation without P");
@@ -5408,15 +5184,14 @@
       ok = gFalse;
     }
   }
-  obj1.free();
 
-  dict->lookupNF("AA", &additionalActions);
+  additionalActions = dict->lookupNF("AA");
 
   appearCharacs = NULL;
-  if(dict->lookup("MK", &obj1)->isDict()) {
+  obj1 = dict->lookup("MK");
+  if (obj1.isDict()) {
     appearCharacs = new AnnotAppearanceCharacs(obj1.getDict());
   }
-  obj1.free();
 }
 
 LinkAction* AnnotScreen::getAdditionalAction(AdditionalActionsType type)
@@ -5435,14 +5210,14 @@
   Object obj1;
 
   type = typeStamp;
-  annotObj.dictSet ("Subtype", obj1.initName ("Stamp"));
+  annotObj.dictSet ("Subtype", Object(objName, "Stamp"));
   initialize(docA, annotObj.getDict());
 }
 
-AnnotStamp::AnnotStamp(PDFDoc *docA, Dict *dict, Object *obj) :
-  AnnotMarkup(docA, dict, obj) {
+AnnotStamp::AnnotStamp(PDFDoc *docA, Object *dictObject, Object *obj) :
+  AnnotMarkup(docA, dictObject, obj) {
   type = typeStamp;
-  initialize(docA, dict);
+  initialize(docA, dictObject->getDict());
 }
 
 AnnotStamp::~AnnotStamp() {
@@ -5450,14 +5225,12 @@
 }
 
 void AnnotStamp::initialize(PDFDoc *docA, Dict* dict) {
-  Object obj1;
-
-  if (dict->lookup("Name", &obj1)->isName()) {
+  Object obj1 = dict->lookup("Name");
+  if (obj1.isName()) {
     icon = new GooString(obj1.getName());
   } else {
     icon = new GooString("Draft");
   }
-  obj1.free();
 
 }
 
@@ -5470,9 +5243,7 @@
     icon = new GooString();
   }
 
-  Object obj1;
-  obj1.initName (icon->getCString());
-  update("Name", &obj1);
+  update("Name", Object(objName, icon->getCString()));
   invalidateAppearance();
 }
 
@@ -5485,10 +5256,10 @@
 
   switch (subType) {
     case typeSquare:
-      annotObj.dictSet ("Subtype", obj1.initName ("Square"));
+      annotObj.dictSet ("Subtype", Object(objName, "Square"));
       break;
     case typeCircle:
-      annotObj.dictSet ("Subtype", obj1.initName ("Circle"));
+      annotObj.dictSet ("Subtype", Object(objName, "Circle"));
       break;
     default:
       assert (0 && "Invalid subtype for AnnotGeometry\n");
@@ -5497,11 +5268,11 @@
   initialize(docA, annotObj.getDict());
 }
 
-AnnotGeometry::AnnotGeometry(PDFDoc *docA, Dict *dict, Object *obj) :
-  AnnotMarkup(docA, dict, obj) {
+AnnotGeometry::AnnotGeometry(PDFDoc *docA, Object *dictObject, Object *obj) :
+  AnnotMarkup(docA, dictObject, obj) {
   // the real type will be read in initialize()
   type = typeSquare;
-  initialize(docA, dict);
+  initialize(docA, dictObject->getDict());
 }
 
 AnnotGeometry::~AnnotGeometry() {
@@ -5513,7 +5284,8 @@
 void AnnotGeometry::initialize(PDFDoc *docA, Dict* dict) {
   Object obj1;
 
-  if (dict->lookup("Subtype", &obj1)->isName()) {
+  obj1 = dict->lookup("Subtype");
+  if (obj1.isName()) {
     GooString typeName(obj1.getName());
     if (!typeName.cmp("Square")) {
       type = typeSquare;
@@ -5521,54 +5293,52 @@
       type = typeCircle;
     }
   }
-  obj1.free();
 
-  if (dict->lookup("IC", &obj1)->isArray()) {
+  obj1 = dict->lookup("IC");
+  if (obj1.isArray()) {
     interiorColor = new AnnotColor(obj1.getArray());
   } else {
     interiorColor = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("BS", &obj1)->isDict()) {
+  obj1 = dict->lookup("BS");
+  if (obj1.isDict()) {
     delete border;
     border = new AnnotBorderBS(obj1.getDict());
   } else if (!border) {
     border = new AnnotBorderBS();
   }
-  obj1.free();
 
-  if (dict->lookup("BE", &obj1)->isDict()) {
+  obj1 = dict->lookup("BE");
+  if (obj1.isDict()) {
     borderEffect = new AnnotBorderEffect(obj1.getDict());
   } else {
     borderEffect = NULL;
   }
-  obj1.free();
 
   geometryRect = NULL;
-  if (dict->lookup("RD", &obj1)->isArray()) {
+  obj1 = dict->lookup("RD");
+  if (obj1.isArray()) {
     geometryRect = parseDiffRectangle(obj1.getArray(), rect);
   }
-  obj1.free();
-
 }
 
 void AnnotGeometry::setType(AnnotSubtype new_type) {
-  Object obj1;
+  const char *typeName;
 
   switch (new_type) {
     case typeSquare:
-      obj1.initName("Square");
+      typeName = "Square";
       break;
     case typeCircle:
-      obj1.initName("Circle");
+      typeName = "Circle";
       break;
     default:
       assert(!"Invalid subtype");
   }
 
   type = new_type;
-  update("Subtype", &obj1);
+  update("Subtype", Object(objName, typeName));
   invalidateAppearance();
 }
 
@@ -5576,9 +5346,8 @@
   delete interiorColor;
 
   if (new_color) {
-    Object obj1;
-    new_color->writeToObject(xref, &obj1);
-    update ("IC", &obj1);
+    Object obj1 = new_color->writeToObject(xref);
+    update ("IC", std::move(obj1));
     interiorColor = new_color;
   } else {
     interiorColor = NULL;
@@ -5587,7 +5356,6 @@
 }
 
 void AnnotGeometry::draw(Gfx *gfx, GBool printing) {
-  Object obj;
   double ca = 1;
 
   if (!isVisible (printing))
@@ -5673,26 +5441,22 @@
     bbox[2] = rect->x2 - rect->x1;
     bbox[3] = rect->y2 - rect->y1;
     if (ca == 1) {
-      createForm(bbox, gFalse, NULL, &appearance);
+      appearance = createForm(bbox, gFalse, nullptr);
     } else {
-      Object aStream;
-
-      createForm(bbox, gTrue, NULL, &aStream);
+      Object aStream = createForm(bbox, gTrue, nullptr);
       delete appearBuf;
 
-      Object resDict;
       appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
-      createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
-      createForm(bbox, gFalse, &resDict, &appearance);
+      Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, NULL);
+      appearance = createForm(bbox, gFalse, resDict);
     }
     delete appearBuf;
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
 		 rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
-  obj.free();
 }
 
 //------------------------------------------------------------------------
@@ -5704,30 +5468,29 @@
 
   switch (subType) {
     case typePolygon:
-      annotObj.dictSet ("Subtype", obj1.initName ("Polygon"));
+      annotObj.dictSet ("Subtype", Object(objName, "Polygon"));
       break;
     case typePolyLine:
-      annotObj.dictSet ("Subtype", obj1.initName ("PolyLine"));
+      annotObj.dictSet ("Subtype", Object(objName, "PolyLine"));
       break;
     default:
       assert (0 && "Invalid subtype for AnnotGeometry\n");
   }
 
   // Store dummy path with one null vertex only
-  Object obj2, obj3;
-  obj2.initArray (doc->getXRef());
-  obj2.arrayAdd (obj3.initReal (0));
-  obj2.arrayAdd (obj3.initReal (0));
-  annotObj.dictSet ("Vertices", &obj2);
+  Array *a = new Array(doc->getXRef());
+  a->add(Object(0.));
+  a->add(Object(0.));
+  annotObj.dictSet("Vertices", Object(a));
 
   initialize(docA, annotObj.getDict());
 }
 
-AnnotPolygon::AnnotPolygon(PDFDoc *docA, Dict *dict, Object *obj) :
-  AnnotMarkup(docA, dict, obj) {
+AnnotPolygon::AnnotPolygon(PDFDoc *docA, Object *dictObject, Object *obj) :
+  AnnotMarkup(docA, dictObject, obj) {
   // the real type will be read in initialize()
   type = typePolygon;
-  initialize(docA, dict);
+  initialize(docA, dictObject->getDict());
 }
 
 AnnotPolygon::~AnnotPolygon() {
@@ -5743,7 +5506,8 @@
 void AnnotPolygon::initialize(PDFDoc *docA, Dict* dict) {
   Object obj1;
 
-  if (dict->lookup("Subtype", &obj1)->isName()) {
+  obj1 = dict->lookup("Subtype");
+  if (obj1.isName()) {
     GooString typeName(obj1.getName());
     if (!typeName.cmp("Polygon")) {
       type = typePolygon;
@@ -5751,60 +5515,58 @@
       type = typePolyLine;
     }
   }
-  obj1.free();
 
-  if (dict->lookup("Vertices", &obj1)->isArray()) {
+  obj1 = dict->lookup("Vertices");
+  if (obj1.isArray()) {
     vertices = new AnnotPath(obj1.getArray());
   } else {
     vertices = new AnnotPath();
     error(errSyntaxError, -1, "Bad Annot Polygon Vertices");
     ok = gFalse;
   }
-  obj1.free();
 
-  if (dict->lookup("LE", &obj1)->isArray() && obj1.arrayGetLength() == 2) {
-    Object obj2;
-
-    if(obj1.arrayGet(0, &obj2)->isString())
+  obj1 = dict->lookup("LE");
+  if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+    Object obj2 = obj1.arrayGet(0);
+    if(obj2.isString())
       startStyle = parseAnnotLineEndingStyle(obj2.getString());
     else
       startStyle = annotLineEndingNone;
-    obj2.free();
 
-    if(obj1.arrayGet(1, &obj2)->isString())
+    obj2 = obj1.arrayGet(1);
+    if(obj2.isString())
       endStyle = parseAnnotLineEndingStyle(obj2.getString());
     else
       endStyle = annotLineEndingNone;
-    obj2.free();
 
   } else {
     startStyle = endStyle = annotLineEndingNone;
   }
-  obj1.free();
 
-  if (dict->lookup("IC", &obj1)->isArray()) {
+  obj1 = dict->lookup("IC");
+  if (obj1.isArray()) {
     interiorColor = new AnnotColor(obj1.getArray());
   } else {
     interiorColor = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("BS", &obj1)->isDict()) {
+  obj1 = dict->lookup("BS");
+  if (obj1.isDict()) {
     delete border;
     border = new AnnotBorderBS(obj1.getDict());
   } else if (!border) {
     border = new AnnotBorderBS();
   }
-  obj1.free();
 
-  if (dict->lookup("BE", &obj1)->isDict()) {
+  obj1 = dict->lookup("BE");
+  if (obj1.isDict()) {
     borderEffect = new AnnotBorderEffect(obj1.getDict());
   } else {
     borderEffect = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("IT", &obj1)->isName()) {
+  obj1 = dict->lookup("IT");
+  if (obj1.isName()) {
     const char *intentName = obj1.getName();
 
     if(!strcmp(intentName, "PolygonCloud")) {
@@ -5817,56 +5579,51 @@
   } else {
     intent = polygonCloud;
   }
-  obj1.free();
 }
 
 void AnnotPolygon::setType(AnnotSubtype new_type) {
-  Object obj1;
+  const char *typeName;
 
   switch (new_type) {
     case typePolygon:
-      obj1.initName("Polygon");
+      typeName = "Polygon";
       break;
     case typePolyLine:
-      obj1.initName("PolyLine");
+      typeName = "PolyLine";
       break;
     default:
       assert(!"Invalid subtype");
   }
 
   type = new_type;
-  update("Subtype", &obj1);
+  update("Subtype", Object(objName, typeName));
   invalidateAppearance();
 }
 
 void AnnotPolygon::setVertices(AnnotPath *path) {
-  Object obj1, obj2;
   delete vertices;
 
-  obj1.initArray(xref);
-
+  Array *a = new Array(xref);
   for (int i = 0; i < path->getCoordsLength(); i++) {
-    obj1.arrayAdd (obj2.initReal (path->getX(i)));
-    obj1.arrayAdd (obj2.initReal (path->getY(i)));
+    a->add(Object(path->getX(i)));
+    a->add(Object(path->getY(i)));
   }
 
-  vertices = new AnnotPath(obj1.getArray());
+  vertices = new AnnotPath(a);
 
-  update("Vertices", &obj1);
+  update("Vertices", Object(a));
   invalidateAppearance();
 }
 
 void AnnotPolygon::setStartEndStyle(AnnotLineEndingStyle start, AnnotLineEndingStyle end) {
-  Object obj1, obj2;
-
   startStyle = start;
   endStyle = end;
 
-  obj1.initArray(xref);
-  obj1.arrayAdd( obj2.initName(convertAnnotLineEndingStyle( startStyle )) );
-  obj1.arrayAdd( obj2.initName(convertAnnotLineEndingStyle( endStyle )) );
+  Array *a = new Array(xref);
+  a->add( Object(objName, convertAnnotLineEndingStyle( startStyle )) );
+  a->add( Object(objName, convertAnnotLineEndingStyle( endStyle )) );
 
-  update("LE", &obj1);
+  update("LE", Object(a));
   invalidateAppearance();
 }
 
@@ -5874,9 +5631,8 @@
   delete interiorColor;
 
   if (new_color) {
-    Object obj1;
-    new_color->writeToObject(xref, &obj1);
-    update ("IC", &obj1);
+    Object obj1 = new_color->writeToObject(xref);
+    update ("IC", std::move(obj1));
     interiorColor = new_color;
   } else {
     interiorColor = NULL;
@@ -5885,20 +5641,19 @@
 }
 
 void AnnotPolygon::setIntent(AnnotPolygonIntent new_intent) {
-  Object obj1;
+  const char *intentName;
 
   intent = new_intent;
   if (new_intent == polygonCloud)
-    obj1.initName("PolygonCloud");
+    intentName = "PolygonCloud";
   else if (new_intent == polylineDimension)
-    obj1.initName("PolyLineDimension");
+    intentName = "PolyLineDimension";
   else // polygonDimension
-    obj1.initName("PolygonDimension");
-  update ("IT", &obj1);
+    intentName = "PolygonDimension";
+  update ("IT", Object(objName, intentName));
 }
 
 void AnnotPolygon::draw(Gfx *gfx, GBool printing) {
-  Object obj;
   double ca = 1;
 
   if (!isVisible (printing))
@@ -5948,22 +5703,20 @@
     double bbox[4];
     appearBBox->getBBoxRect(bbox);
     if (ca == 1) {
-      createForm(bbox, gFalse, NULL, &appearance);
+      appearance = createForm(bbox, gFalse, nullptr);
     } else {
-      Object aStream, resDict;
-
-      createForm(bbox, gTrue, NULL, &aStream);
+      Object aStream = createForm(bbox, gTrue, nullptr);
       delete appearBuf;
 
       appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
-      createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
-      createForm(bbox, gFalse, &resDict, &appearance);
+      Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, NULL);
+      appearance = createForm(bbox, gFalse, resDict);
     }
     delete appearBuf;
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   if (appearBBox) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    appearBBox->getPageXMin(), appearBBox->getPageYMin(),
@@ -5973,7 +5726,6 @@
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   }
-  obj.free();
 }
 
 //------------------------------------------------------------------------
@@ -5985,14 +5737,14 @@
 
   type = typeCaret;
 
-  annotObj.dictSet ("Subtype", obj1.initName ("Caret"));
+  annotObj.dictSet ("Subtype", Object(objName, "Caret"));
   initialize(docA, annotObj.getDict());
 }
 
-AnnotCaret::AnnotCaret(PDFDoc *docA, Dict *dict, Object *obj) :
-  AnnotMarkup(docA, dict, obj) {
+AnnotCaret::AnnotCaret(PDFDoc *docA, Object *dictObject, Object *obj) :
+  AnnotMarkup(docA, dictObject, obj) {
   type = typeCaret;
-  initialize(docA, dict);
+  initialize(docA, dictObject->getDict());
 }
 
 AnnotCaret::~AnnotCaret() {
@@ -6003,7 +5755,8 @@
   Object obj1;
 
   symbol = symbolNone;
-  if (dict->lookup("Sy", &obj1)->isName()) {
+  obj1 = dict->lookup("Sy");
+  if (obj1.isName()) {
     GooString typeName(obj1.getName());
     if (!typeName.cmp("P")) {
       symbol = symbolP;
@@ -6011,22 +5764,18 @@
       symbol = symbolNone;
     }
   }
-  obj1.free();
 
-  if (dict->lookup("RD", &obj1)->isArray()) {
+  obj1 = dict->lookup("RD");
+  if (obj1.isArray()) {
     caretRect = parseDiffRectangle(obj1.getArray(), rect);
   } else {
     caretRect = NULL;
   }
-  obj1.free();
-
 }
 
 void AnnotCaret::setSymbol(AnnotCaretSymbol new_symbol) {
-  Object obj1;
-  obj1.initName( new_symbol == symbolP ? "P" : "None" );
   symbol = new_symbol;
-  update("Sy", &obj1);
+  update("Sy", Object(objName, new_symbol == symbolP ? "P" : "None"));
   invalidateAppearance();
 }
 
@@ -6039,23 +5788,24 @@
 
   type = typeInk;
 
-  annotObj.dictSet ("Subtype", obj1.initName ("Ink"));
+  annotObj.dictSet ("Subtype", Object(objName, "Ink"));
 
   // Store dummy path with one null vertex only
-  Object obj2, obj3, obj4;
-  obj2.initArray (doc->getXRef());
-  obj2.arrayAdd (obj3.initArray (doc->getXRef()));
-  obj3.arrayAdd (obj4.initReal (0));
-  obj3.arrayAdd (obj4.initReal (0));
-  annotObj.dictSet ("InkList", &obj2);
+  Object obj3, obj4;
+  Array *inkList = new Array(doc->getXRef());
+  Array *vList = new Array(doc->getXRef());
+  vList->add(Object(0.));
+  vList->add(Object(0.));
+  inkList->add(Object(vList));
+  annotObj.dictSet("InkList", Object(inkList));
 
   initialize(docA, annotObj.getDict());
 }
 
-AnnotInk::AnnotInk(PDFDoc *docA, Dict *dict, Object *obj) :
-  AnnotMarkup(docA, dict, obj) {
+AnnotInk::AnnotInk(PDFDoc *docA, Object *dictObject, Object *obj) :
+  AnnotMarkup(docA, dictObject, obj) {
   type = typeInk;
-  initialize(docA, dict);
+  initialize(docA, dictObject->getDict());
 }
 
 AnnotInk::~AnnotInk() {
@@ -6065,7 +5815,8 @@
 void AnnotInk::initialize(PDFDoc *docA, Dict* dict) {
   Object obj1;
 
-  if (dict->lookup("InkList", &obj1)->isArray()) {
+  obj1 = dict->lookup("InkList");
+  if (obj1.isArray()) {
     parseInkList(obj1.getArray());
   } else {
     inkListLength = 0;
@@ -6073,27 +5824,25 @@
     error(errSyntaxError, -1, "Bad Annot Ink List");
     ok = gFalse;
   }
-  obj1.free();
 
-  if (dict->lookup("BS", &obj1)->isDict()) {
+  obj1 = dict->lookup("BS");
+  if (obj1.isDict()) {
     delete border;
     border = new AnnotBorderBS(obj1.getDict());
   } else if (!border) {
     border = new AnnotBorderBS();
   }
-  obj1.free();
 }
 
 void AnnotInk::writeInkList(AnnotPath **paths, int n_paths, Array *dest_array) {
-  Object obj1, obj2;
   for (int i = 0; i < n_paths; ++i) {
     AnnotPath *path = paths[i];
-    obj1.initArray (xref);
+    Array *a = new Array(xref);
     for (int j = 0; j < path->getCoordsLength(); ++j) {
-      obj1.arrayAdd (obj2.initReal (path->getX(j)));
-      obj1.arrayAdd (obj2.initReal (path->getY(j)));
+      a->add(Object(path->getX(j)));
+      a->add(Object(path->getY(j)));
     }
-    dest_array->add (&obj1);
+    dest_array->add(Object(a));
   }
 }
 
@@ -6102,10 +5851,9 @@
   inkList = (AnnotPath **) gmallocn ((inkListLength), sizeof(AnnotPath *));
   memset(inkList, 0, inkListLength * sizeof(AnnotPath *));
   for (int i = 0; i < inkListLength; i++) {
-    Object obj2;
-    if (array->get(i, &obj2)->isArray())
+    Object obj2 = array->get(i);
+    if (obj2.isArray())
       inkList[i] = new AnnotPath(obj2.getArray());
-    obj2.free();
   }
 }
 
@@ -6118,20 +5866,17 @@
 }
 
 void AnnotInk::setInkList(AnnotPath **paths, int n_paths) {
-  Object obj1;
-
   freeInkList();
 
-  obj1.initArray (xref);
-  writeInkList(paths, n_paths, obj1.getArray());
+  Array *a = new Array(xref);
+  writeInkList(paths, n_paths, a);
 
-  parseInkList(obj1.getArray());
-  annotObj.dictSet ("InkList", &obj1);
+  parseInkList(a);
+  annotObj.dictSet ("InkList", Object(a));
   invalidateAppearance();
 }
 
 void AnnotInk::draw(Gfx *gfx, GBool printing) {
-  Object obj;
   double ca = 1;
 
   if (!isVisible (printing))
@@ -6172,22 +5917,20 @@
     double bbox[4];
     appearBBox->getBBoxRect(bbox);
     if (ca == 1) {
-      createForm(bbox, gFalse, NULL, &appearance);
+      appearance = createForm(bbox, gFalse, nullptr);
     } else {
-      Object aStream, resDict;
-
-      createForm(bbox, gTrue, NULL, &aStream);
+      Object aStream = createForm(bbox, gTrue, nullptr);
       delete appearBuf;
 
       appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
-      createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
-      createForm(bbox, gFalse, &resDict, &appearance);
+      Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, NULL);
+      appearance = createForm(bbox, gFalse, resDict);
     }
     delete appearBuf;
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   if (appearBBox) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    appearBBox->getPageXMin(), appearBBox->getPageYMin(),
@@ -6197,7 +5940,6 @@
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   }
-  obj.free();
 }
 
 //------------------------------------------------------------------------
@@ -6209,45 +5951,39 @@
 
   type = typeFileAttachment;
 
-  annotObj.dictSet ("Subtype", obj1.initName ("FileAttachment"));
-
-  Object obj2;
-  obj2.initString(filename->copy());
-  annotObj.dictSet ("FS", &obj2);
+  annotObj.dictSet("Subtype", Object(objName, "FileAttachment"));
+  annotObj.dictSet("FS", Object(filename->copy()));
 
   initialize(docA, annotObj.getDict());
 }
 
-AnnotFileAttachment::AnnotFileAttachment(PDFDoc *docA, Dict *dict, Object *obj) :
-  AnnotMarkup(docA, dict, obj) {
+AnnotFileAttachment::AnnotFileAttachment(PDFDoc *docA, Object *dictObject, Object *obj) :
+  AnnotMarkup(docA, dictObject, obj) {
   type = typeFileAttachment;
-  initialize(docA, dict);
+  initialize(docA, dictObject->getDict());
 }
 
 AnnotFileAttachment::~AnnotFileAttachment() {
-  file.free();
-
-  if (name)
-    delete name;
+  delete name;
 }
 
 void AnnotFileAttachment::initialize(PDFDoc *docA, Dict* dict) {
   Object obj1;
 
-  if (dict->lookup("FS", &obj1)->isDict() || dict->lookup("FS", &obj1)->isString()) {
-    obj1.copy(&file);
+  obj1 = dict->lookup("FS");
+  if (obj1.isDict() || obj1.isString()) {
+    file = obj1.copy();
   } else {
     error(errSyntaxError, -1, "Bad Annot File Attachment");
     ok = gFalse;
   }
-  obj1.free();
 
-  if (dict->lookup("Name", &obj1)->isName()) {
+  obj1 = dict->lookup("Name");
+  if (obj1.isName()) {
     name = new GooString(obj1.getName());
   } else {
     name = new GooString("PushPin");
   }
-  obj1.free();
 }
 
 #define ANNOT_FILE_ATTACHMENT_AP_PUSHPIN                                         \
@@ -6363,7 +6099,6 @@
   "19.5 17.699 20.91 17.418 22.5 17.5 c S\n"
 
 void AnnotFileAttachment::draw(Gfx *gfx, GBool printing) {
-  Object obj;
   double ca = 1;
 
   if (!isVisible (printing))
@@ -6394,26 +6129,22 @@
     bbox[0] = bbox[1] = 0;
     bbox[2] = bbox[3] = 24;
     if (ca == 1) {
-      createForm (bbox, gFalse, NULL, &appearance);
+      appearance = createForm (bbox, gFalse, nullptr);
     } else {
-      Object aStream;
-
-      createForm (bbox, gTrue, NULL, &aStream);
+      Object aStream = createForm (bbox, gTrue, nullptr);
       delete appearBuf;
 
-      Object resDict;
       appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
-      createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
-      createForm(bbox, gFalse, &resDict, &appearance);
+      Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, NULL);
+      appearance = createForm(bbox, gFalse, resDict);
     }
     delete appearBuf;
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
 		 rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
-  obj.free();
 }
 
 //------------------------------------------------------------------------
@@ -6425,21 +6156,16 @@
 
   type = typeSound;
 
-  annotObj.dictSet ("Subtype", obj1.initName ("Sound"));
-
-  Object obj2;
-  Stream *str = soundA->getStream();
-  obj2.initStream (str);
-  str->incRef(); //FIXME: initStream should do this?
-  annotObj.dictSet ("Sound", &obj2);
+  annotObj.dictSet ("Subtype", Object(objName, "Sound"));
+  annotObj.dictSet ("Sound", soundA->getObject()->copy());
 
   initialize(docA, annotObj.getDict());
 }
 
-AnnotSound::AnnotSound(PDFDoc *docA, Dict *dict, Object *obj) :
-  AnnotMarkup(docA, dict, obj) {
+AnnotSound::AnnotSound(PDFDoc *docA, Object *dictObject, Object *obj) :
+  AnnotMarkup(docA, dictObject, obj) {
   type = typeSound;
-  initialize(docA, dict);
+  initialize(docA, dictObject->getDict());
 }
 
 AnnotSound::~AnnotSound() {
@@ -6449,21 +6175,20 @@
 }
 
 void AnnotSound::initialize(PDFDoc *docA, Dict* dict) {
-  Object obj1;
+  Object obj1 = dict->lookup("Sound");
 
-  sound = Sound::parseSound(dict->lookup("Sound", &obj1));
+  sound = Sound::parseSound(&obj1);
   if (!sound) {
     error(errSyntaxError, -1, "Bad Annot Sound");
     ok = gFalse;
   }
-  obj1.free();
 
-  if (dict->lookup("Name", &obj1)->isName()) {
+  obj1 = dict->lookup("Name");
+  if (obj1.isName()) {
     name = new GooString(obj1.getName());
   } else {
     name = new GooString("Speaker");
   }
-  obj1.free();
 }
 
 #define ANNOT_SOUND_AP_SPEAKER                                               \
@@ -6557,25 +6282,22 @@
     bbox[0] = bbox[1] = 0;
     bbox[2] = bbox[3] = 24;
     if (ca == 1) {
-      createForm(bbox, gFalse, NULL, &appearance);
+      appearance = createForm(bbox, gFalse, nullptr);
     } else {
-      Object aStream, resDict;
-
-      createForm(bbox, gTrue, NULL, &aStream);
+      Object aStream = createForm(bbox, gTrue, nullptr);
       delete appearBuf;
 
       appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
-      createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
-      createForm(bbox, gFalse, &resDict, &appearance);
+      Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, NULL);
+      appearance = createForm(bbox, gFalse, resDict);
     }
     delete appearBuf;
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  obj = appearance.fetch(gfx->getXRef());
   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
 		 rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
-  obj.free();
 }
 
 //------------------------------------------------------------------------
@@ -6587,15 +6309,15 @@
 
   type = type3D;
 
-  annotObj.dictSet ("Subtype", obj1.initName ("3D"));
+  annotObj.dictSet ("Subtype", Object(objName, "3D"));
 
   initialize(docA, annotObj.getDict());
 }
 
-Annot3D::Annot3D(PDFDoc *docA, Dict *dict, Object *obj) :
-  Annot(docA, dict, obj) {
+Annot3D::Annot3D(PDFDoc *docA, Object *dictObject, Object *obj) :
+  Annot(docA, dictObject, obj) {
   type = type3D;
-  initialize(docA, dict);
+  initialize(docA, dictObject->getDict());
 }
 
 Annot3D::~Annot3D() {
@@ -6604,20 +6326,19 @@
 }
 
 void Annot3D::initialize(PDFDoc *docA, Dict* dict) {
-  Object obj1;
-
-  if (dict->lookup("3DA", &obj1)->isDict()) {
+  Object obj1 = dict->lookup("3DA");
+  if (obj1.isDict()) {
     activation = new Activation(obj1.getDict());
   } else {
     activation = NULL;
   }
-  obj1.free();
 }
 
 Annot3D::Activation::Activation(Dict *dict) {
   Object obj1;
 
-  if (dict->lookup("A", &obj1)->isName()) {
+  obj1 = dict->lookup("A");
+  if (obj1.isName()) {
     const char *name = obj1.getName();
 
     if(!strcmp(name, "PO")) {
@@ -6632,9 +6353,9 @@
   } else {
     aTrigger = aTriggerUnknown;
   }
-  obj1.free();
 
-  if(dict->lookup("AIS", &obj1)->isName()) {
+  obj1 = dict->lookup("AIS");
+  if (obj1.isName()) {
     const char *name = obj1.getName();
 
     if(!strcmp(name, "I")) {
@@ -6647,9 +6368,9 @@
   } else {
     aState = aStateUnknown;
   }
-  obj1.free();
 
-  if(dict->lookup("D", &obj1)->isName()) {
+  obj1 = dict->lookup("D");
+  if (obj1.isName()) {
     const char *name = obj1.getName();
 
     if(!strcmp(name, "PC")) {
@@ -6664,9 +6385,9 @@
   } else {
     dTrigger = dTriggerUnknown;
   }
-  obj1.free();
 
-  if(dict->lookup("DIS", &obj1)->isName()) {
+  obj1 = dict->lookup("DIS");
+  if (obj1.isName()) {
     const char *name = obj1.getName();
 
     if(!strcmp(name, "U")) {
@@ -6681,21 +6402,20 @@
   } else {
     dState = dStateUnknown;
   }
-  obj1.free();
 
-  if (dict->lookup("TB", &obj1)->isBool()) {
+  obj1 = dict->lookup("TB");
+  if (obj1.isBool()) {
     displayToolbar = obj1.getBool();
   } else {
     displayToolbar = gTrue;
   }
-  obj1.free();
 
-  if (dict->lookup("NP", &obj1)->isBool()) {
+  obj1 = dict->lookup("NP");
+  if (obj1.isBool()) {
     displayNavigation = obj1.getBool();
   } else {
     displayNavigation = gFalse;
   }
-  obj1.free();
 }
 
 //------------------------------------------------------------------------
@@ -6707,15 +6427,15 @@
 
   type = typeRichMedia;
 
-  annotObj.dictSet ("Subtype", obj1.initName ("RichMedia"));
+  annotObj.dictSet ("Subtype", Object(objName, "RichMedia"));
 
   initialize(docA, annotObj.getDict());
 }
 
-AnnotRichMedia::AnnotRichMedia(PDFDoc *docA, Dict *dict, Object *obj) :
-  Annot(docA, dict, obj) {
+AnnotRichMedia::AnnotRichMedia(PDFDoc *docA, Object *dictObject, Object *obj) :
+  Annot(docA, dictObject, obj) {
   type = typeRichMedia;
-  initialize(docA, dict);
+  initialize(docA, dictObject->getDict());
 }
 
 AnnotRichMedia::~AnnotRichMedia() {
@@ -6724,21 +6444,19 @@
 }
 
 void AnnotRichMedia::initialize(PDFDoc *docA, Dict* dict) {
-  Object obj1;
-
-  if (dict->lookup("RichMediaContent", &obj1)->isDict()) {
+  Object obj1 = dict->lookup("RichMediaContent");
+  if (obj1.isDict()) {
     content = new AnnotRichMedia::Content(obj1.getDict());
   } else {
     content = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("RichMediaSettings", &obj1)->isDict()) {
+  obj1 = dict->lookup("RichMediaSettings");
+  if (obj1.isDict()) {
     settings = new AnnotRichMedia::Settings(obj1.getDict());
   } else {
     settings = NULL;
   }
-  obj1.free();
 }
 
 AnnotRichMedia::Content* AnnotRichMedia::getContent() const {
@@ -6750,21 +6468,19 @@
 }
 
 AnnotRichMedia::Settings::Settings(Dict *dict) {
-  Object obj1;
-
-  if (dict->lookup("Activation", &obj1)->isDict()) {
+  Object obj1 = dict->lookup("Activation");
+  if (obj1.isDict()) {
     activation = new AnnotRichMedia::Activation(obj1.getDict());
   } else {
     activation = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("Deactivation", &obj1)->isDict()) {
+  obj1 = dict->lookup("Deactivation");
+  if (obj1.isDict()) {
     deactivation = new AnnotRichMedia::Deactivation(obj1.getDict());
   } else {
     deactivation = NULL;
   }
-  obj1.free();
 }
 
 AnnotRichMedia::Settings::~Settings() {
@@ -6781,9 +6497,8 @@
 }
 
 AnnotRichMedia::Activation::Activation(Dict *dict) {
-  Object obj1;
-
-  if (dict->lookup("Condition", &obj1)->isName()) {
+  Object obj1 = dict->lookup("Condition");
+  if (obj1.isName()) {
     const char *name = obj1.getName();
 
     if (!strcmp(name, "PO")) {
@@ -6798,7 +6513,6 @@
   } else {
     condition = conditionUserAction;
   }
-  obj1.free();
 }
 
 AnnotRichMedia::Activation::Condition AnnotRichMedia::Activation::getCondition() const {
@@ -6806,9 +6520,8 @@
 }
 
 AnnotRichMedia::Deactivation::Deactivation(Dict *dict) {
-  Object obj1;
-
-  if (dict->lookup("Condition", &obj1)->isName()) {
+  Object obj1 = dict->lookup("Condition");
+  if (obj1.isName()) {
     const char *name = obj1.getName();
 
     if (!strcmp(name, "PC")) {
@@ -6823,7 +6536,6 @@
   } else {
     condition = conditionUserAction;
   }
-  obj1.free();
 }
 
 AnnotRichMedia::Deactivation::Condition AnnotRichMedia::Deactivation::getCondition() const {
@@ -6831,57 +6543,48 @@
 }
 
 AnnotRichMedia::Content::Content(Dict *dict) {
-  Object obj1;
-
-  if (dict->lookup("Configurations", &obj1)->isArray()) {
+  Object obj1 = dict->lookup("Configurations");
+  if (obj1.isArray()) {
     nConfigurations = obj1.arrayGetLength();
 
     configurations = (Configuration **)gmallocn(nConfigurations, sizeof(Configuration *));
 
     for (int i = 0; i < nConfigurations; ++i) {
-      Object obj2;
-
-      if (obj1.arrayGet(i, &obj2)->isDict()) {
+      Object obj2 = obj1.arrayGet(i);
+      if (obj2.isDict()) {
         configurations[i] = new AnnotRichMedia::Configuration(obj2.getDict());
       } else {
         configurations[i] = NULL;
       }
-      obj2.free();
     }
   } else {
     nConfigurations = 0;
     configurations = NULL;
   }
-  obj1.free();
 
   nAssets = 0;
   assets = NULL;
-  if (dict->lookup("Assets", &obj1)->isDict()) {
-    Object obj2;
-
-    if (obj1.getDict()->lookup("Names", &obj2)->isArray()) {
+  obj1 = dict->lookup("Assets");
+  if (obj1.isDict()) {
+    Object obj2 = obj1.getDict()->lookup("Names");
+    if (obj2.isArray()) {
       nAssets = obj2.arrayGetLength() / 2;
 
       assets = (Asset **)gmallocn(nAssets, sizeof(Asset *));
 
       int counter = 0;
       for (int i = 0; i < obj2.arrayGetLength(); i += 2) {
-        Object objKey;
-
         assets[counter] = new AnnotRichMedia::Asset;
 
-        obj2.arrayGet(i, &objKey);
-        obj2.arrayGet(i + 1, &assets[counter]->fileSpec);
+        Object objKey = obj2.arrayGet(i);
+        assets[counter]->fileSpec = obj2.arrayGet(i + 1);
 
         assets[counter]->name = new GooString( objKey.getString() );
         ++counter;
 
-        objKey.free();
       }
     }
-    obj2.free();
   }
-  obj1.free();
 }
 
 AnnotRichMedia::Content::~Content() {
@@ -6928,7 +6631,6 @@
 AnnotRichMedia::Asset::~Asset()
 {
   delete name;
-  fileSpec.free();
 }
 
 GooString* AnnotRichMedia::Asset::getName() const {
@@ -6941,36 +6643,33 @@
 
 AnnotRichMedia::Configuration::Configuration(Dict *dict)
 {
-  Object obj1;
-
-  if (dict->lookup("Instances", &obj1)->isArray()) {
+  Object obj1 = dict->lookup("Instances");
+  if (obj1.isArray()) {
     nInstances = obj1.arrayGetLength();
 
     instances = (Instance **)gmallocn(nInstances, sizeof(Instance *));
 
     for (int i = 0; i < nInstances; ++i) {
-      Object obj2;
-
-      if (obj1.arrayGet(i, &obj2)->isDict()) {
+      Object obj2 = obj1.arrayGet(i);
+      if (obj2.isDict()) {
         instances[i] = new AnnotRichMedia::Instance(obj2.getDict());
       } else {
         instances[i] = NULL;
       }
-      obj2.free();
     }
   } else {
     instances = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("Name", &obj1)->isString()) {
+  obj1 = dict->lookup("Name");
+  if (obj1.isString()) {
     name = new GooString(obj1.getString());
   } else {
     name = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("Subtype", &obj1)->isName()) {
+  obj1 = dict->lookup("Subtype");
+  if (obj1.isName()) {
     const char *name = obj1.getName();
 
     if (!strcmp(name, "3D")) {
@@ -7005,7 +6704,6 @@
       }
     }
   }
-  obj1.free();
 }
 
 AnnotRichMedia::Configuration::~Configuration()
@@ -7040,9 +6738,7 @@
 
 AnnotRichMedia::Instance::Instance(Dict *dict)
 {
-  Object obj1;
-
-  dict->lookup("Subtype", &obj1);
+  Object obj1 = dict->lookup("Subtype");
   const char *name = obj1.isName() ? obj1.getName() : "";
 
   if (!strcmp(name, "3D")) {
@@ -7056,14 +6752,13 @@
   } else {
     type = typeFlash;
   }
-  obj1.free();
 
-  if (dict->lookup("Params", &obj1)->isDict()) {
+  obj1 = dict->lookup("Params");
+  if (obj1.isDict()) {
     params = new AnnotRichMedia::Params(obj1.getDict());
   } else {
     params = NULL;
   }
-  obj1.free();
 }
 
 AnnotRichMedia::Instance::~Instance()
@@ -7081,14 +6776,12 @@
 
 AnnotRichMedia::Params::Params(Dict *dict)
 {
-  Object obj1;
-
-  if (dict->lookup("FlashVars", &obj1)->isString()) {
+  Object obj1 = dict->lookup("FlashVars");
+  if (obj1.isString()) {
     flashVars = new GooString(obj1.getString());
   } else {
     flashVars = NULL;
   }
-  obj1.free();
 }
 
 AnnotRichMedia::Params::~Params()
@@ -7106,7 +6799,6 @@
 
 Annots::Annots(PDFDoc *docA, int page, Object *annotsObj) {
   Annot *annot;
-  Object obj1;
   int i;
 
   doc = docA;
@@ -7119,10 +6811,10 @@
       //get the Ref to this annot and pass it to Annot constructor 
       //this way, it'll be possible for the annot to retrieve the corresponding
       //form widget
-      Object obj2;
-      if (annotsObj->arrayGet(i, &obj1)->isDict()) {
-        annotsObj->arrayGetNF(i, &obj2);
-        annot = createAnnot (obj1.getDict(), &obj2);
+      Object obj1 = annotsObj->arrayGet(i);
+      if (obj1.isDict()) {
+	Object obj2 = annotsObj->arrayGetNF(i);
+        annot = createAnnot (&obj1, &obj2);
         if (annot) {
           if (annot->isOk()) {
             annot->setPage(page, gFalse); // Don't change /P
@@ -7131,8 +6823,6 @@
           annot->decRefCnt();
         }
       }
-      obj2.free();
-      obj1.free();
     }
   }
 }
@@ -7166,49 +6856,48 @@
   }
 }
 
-Annot *Annots::createAnnot(Dict* dict, Object *obj) {
-  Annot *annot = NULL;
-  Object obj1;
-
-  if (dict->lookup("Subtype", &obj1)->isName()) {
+Annot *Annots::createAnnot(Object* dictObject, Object *obj) {
+  Annot *annot = nullptr;
+  Object obj1 = dictObject->dictLookup("Subtype");
+  if (obj1.isName()) {
     const char *typeName = obj1.getName();
 
     if (!strcmp(typeName, "Text")) {
-      annot = new AnnotText(doc, dict, obj);
+      annot = new AnnotText(doc, dictObject, obj);
     } else if (!strcmp(typeName, "Link")) {
-      annot = new AnnotLink(doc, dict, obj);
+      annot = new AnnotLink(doc, dictObject, obj);
     } else if (!strcmp(typeName, "FreeText")) {
-      annot = new AnnotFreeText(doc, dict, obj);
+      annot = new AnnotFreeText(doc, dictObject, obj);
     } else if (!strcmp(typeName, "Line")) {
-      annot = new AnnotLine(doc, dict, obj);
+      annot = new AnnotLine(doc, dictObject, obj);
     } else if (!strcmp(typeName, "Square")) {
-      annot = new AnnotGeometry(doc, dict, obj);
+      annot = new AnnotGeometry(doc, dictObject, obj);
     } else if (!strcmp(typeName, "Circle")) {
-      annot = new AnnotGeometry(doc, dict, obj);
+      annot = new AnnotGeometry(doc, dictObject, obj);
     } else if (!strcmp(typeName, "Polygon")) {
-      annot = new AnnotPolygon(doc, dict, obj);
+      annot = new AnnotPolygon(doc, dictObject, obj);
     } else if (!strcmp(typeName, "PolyLine")) {
-      annot = new AnnotPolygon(doc, dict, obj);
+      annot = new AnnotPolygon(doc, dictObject, obj);
     } else if (!strcmp(typeName, "Highlight")) {
-      annot = new AnnotTextMarkup(doc, dict, obj);
+      annot = new AnnotTextMarkup(doc, dictObject, obj);
     } else if (!strcmp(typeName, "Underline")) {
-      annot = new AnnotTextMarkup(doc, dict, obj);
+      annot = new AnnotTextMarkup(doc, dictObject, obj);
     } else if (!strcmp(typeName, "Squiggly")) {
-      annot = new AnnotTextMarkup(doc, dict, obj);
+      annot = new AnnotTextMarkup(doc, dictObject, obj);
     } else if (!strcmp(typeName, "StrikeOut")) {
-      annot = new AnnotTextMarkup(doc, dict, obj);
+      annot = new AnnotTextMarkup(doc, dictObject, obj);
     } else if (!strcmp(typeName, "Stamp")) {
-      annot = new AnnotStamp(doc, dict, obj);
+      annot = new AnnotStamp(doc, dictObject, obj);
     } else if (!strcmp(typeName, "Caret")) {
-      annot = new AnnotCaret(doc, dict, obj);
+      annot = new AnnotCaret(doc, dictObject, obj);
     } else if (!strcmp(typeName, "Ink")) {
-      annot = new AnnotInk(doc, dict, obj);
+      annot = new AnnotInk(doc, dictObject, obj);
     } else if (!strcmp(typeName, "FileAttachment")) {
-      annot = new AnnotFileAttachment(doc, dict, obj);
+      annot = new AnnotFileAttachment(doc, dictObject, obj);
     } else if (!strcmp(typeName, "Sound")) {
-      annot = new AnnotSound(doc, dict, obj);
+      annot = new AnnotSound(doc, dictObject, obj);
     } else if(!strcmp(typeName, "Movie")) {
-      annot = new AnnotMovie(doc, dict, obj);
+      annot = new AnnotMovie(doc, dictObject, obj);
     } else if(!strcmp(typeName, "Widget")) {
       // Find the annot in forms
       if (obj->isRef()) {
@@ -7222,37 +6911,33 @@
         }
       }
       if (!annot)
-        annot = new AnnotWidget(doc, dict, obj);
+        annot = new AnnotWidget(doc, dictObject, obj);
     } else if(!strcmp(typeName, "Screen")) {
-      annot = new AnnotScreen(doc, dict, obj);
+      annot = new AnnotScreen(doc, dictObject, obj);
     } else if(!strcmp(typeName, "PrinterMark")) {
-      annot = new Annot(doc, dict, obj);
+      annot = new Annot(doc, dictObject, obj);
     } else if (!strcmp(typeName, "TrapNet")) {
-      annot = new Annot(doc, dict, obj);
+      annot = new Annot(doc, dictObject, obj);
     } else if (!strcmp(typeName, "Watermark")) {
-      annot = new Annot(doc, dict, obj);
+      annot = new Annot(doc, dictObject, obj);
     } else if (!strcmp(typeName, "3D")) {
-      annot = new Annot3D(doc, dict, obj);
+      annot = new Annot3D(doc, dictObject, obj);
     } else if (!strcmp(typeName, "RichMedia")) {
-      annot = new AnnotRichMedia(doc, dict, obj);
+      annot = new AnnotRichMedia(doc, dictObject, obj);
     } else if (!strcmp(typeName, "Popup")) {
       /* Popup annots are already handled by markup annots
        * Here we only care about popup annots without a
        * markup annotation associated
        */
-      Object obj2;
-
-      if (dict->lookup("Parent", &obj2)->isNull())
-        annot = new AnnotPopup(doc, dict, obj);
+      Object obj2 = dictObject->dictLookup("Parent");
+      if (obj2.isNull())
+        annot = new AnnotPopup(doc, dictObject, obj);
       else
         annot = NULL;
-      
-      obj2.free();
     } else {
-      annot = new Annot(doc, dict, obj);
+      annot = new Annot(doc, dictObject, obj);
     }
   }
-  obj1.free();
 
   return annot;
 }
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 87ba9c3..171494a 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -21,7 +21,7 @@
 // Copyright (C) 2008 Hugo Mercier <hmercier31@gmail.com>
 // Copyright (C) 2008 Pino Toscano <pino@kde.org>
 // Copyright (C) 2008 Tomas Are Haavet <tomasare@gmail.com>
-// Copyright (C) 2009-2011, 2013, 2016 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2009-2011, 2013, 2016, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it>
 // Copyright (C) 2012, 2015 Tobias Koenig <tokoe@kdab.com>
 // Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
@@ -239,7 +239,7 @@
   virtual double *getDash() const { return dash; }
   virtual AnnotBorderStyle getStyle() const { return style; }
 
-  virtual void writeToObject(XRef *xref, Object *obj1) const = 0;
+  virtual Object writeToObject(XRef *xref) const = 0;
 
 protected:
   AnnotBorder();
@@ -271,7 +271,7 @@
 
 private:
   AnnotBorderType getType() const override { return typeArray; }
-  void writeToObject(XRef *xref, Object *obj1) const override;
+  Object writeToObject(XRef *xref) const override;
 
   double horizontalCorner;          // (Default 0)
   double verticalCorner;            // (Default 0)
@@ -290,7 +290,7 @@
 
 private:
   AnnotBorderType getType() const override { return typeBS; }
-  void writeToObject(XRef *xref, Object *obj1) const override;
+  Object writeToObject(XRef *xref) const override;
 
   const char *getStyleName() const;
 
@@ -324,7 +324,7 @@
   AnnotColorSpace getSpace() const { return (AnnotColorSpace) length; }
   const double *getValues() const { return values; }
 
-  void writeToObject(XRef *xref, Object *dest) const;
+  Object writeToObject(XRef *xref) const;
 
 private:
 
@@ -385,7 +385,7 @@
   ~AnnotAppearance();
 
   // State is ignored if no subdictionary is present
-  void getAppearanceStream(AnnotAppearanceType type, const char *state, Object *dest);
+  Object getAppearanceStream(AnnotAppearanceType type, const char *state);
 
   // Access keys in normal appearance subdictionary (N)
   GooString * getStateKey(int i);
@@ -555,8 +555,8 @@
   };
 
   Annot(PDFDoc *docA, PDFRectangle *rectA);
-  Annot(PDFDoc *docA, Dict *dict);
-  Annot(PDFDoc *docA, Dict *dict, Object *obj);
+  Annot(PDFDoc *docA, Object *dictObject);
+  Annot(PDFDoc *docA, Object *dictObject, Object *obj);
   GBool isOk() { return ok; }
 
   void incRefCnt();
@@ -564,7 +564,7 @@
 
   virtual void draw(Gfx *gfx, GBool printing);
   // Get the resource dict of the appearance stream
-  virtual Object *getAppearanceResDict(Object *dest);
+  virtual Object getAppearanceResDict();
 
   GBool match(Ref *refA)
     { return ref.num == refA->num && ref.gen == refA->gen; }
@@ -638,15 +638,15 @@
 		  double *width, double widthLimit, int *charCount,
 		  GBool noReencode);
   void writeString(GooString *str, GooString *appearBuf);
-  void createForm(double *bbox, GBool transparencyGroup, Object *resDict, Object *aStream);
-  void createResourcesDict(const char *formName, Object *formStream, const char *stateName,
-			   double opacity, const char *blendMode, Object *resDict);
+  Object createForm(double *bbox, GBool transparencyGroup, Dict *resDict);
+  Dict *createResourcesDict(const char *formName, Object &&formStream, const char *stateName,
+			   double opacity, const char *blendMode);
   GBool isVisible(GBool printing);
   int getRotation() const;
 
   // Updates the field key of the annotation dictionary
   // and sets M to the current time
-  void update(const char *key, Object *value);
+  void update(const char *key, Object &&value);
 
   // Delete appearance streams and reset appearance state
   void invalidateAppearance();
@@ -695,10 +695,9 @@
 class AnnotPopup: public Annot {
 public:
   AnnotPopup(PDFDoc *docA, PDFRectangle *rect);
-  AnnotPopup(PDFDoc *docA, Dict *dict, Object *obj);
+  AnnotPopup(PDFDoc *docA, Object *dictObject, Object *obj);
   ~AnnotPopup();
 
-  Object *getParent(Object *obj) { return parent.fetch (xref, obj); }
   Object *getParentNF() { return &parent; }
   void setParent(Object *parentA);
   void setParent(Annot *parentA);
@@ -724,7 +723,7 @@
   };
 
   AnnotMarkup(PDFDoc *docA, PDFRectangle *rect);
-  AnnotMarkup(PDFDoc *docA, Dict *dict, Object *obj);
+  AnnotMarkup(PDFDoc *docA, Object *dictObject, Object *obj);
   ~AnnotMarkup();
 
   // getters
@@ -784,7 +783,7 @@
   };
 
   AnnotText(PDFDoc *docA, PDFRectangle *rect);
-  AnnotText(PDFDoc *docA, Dict *dict, Object *obj);
+  AnnotText(PDFDoc *docA, Object *dictObject, Object *obj);
   ~AnnotText();
 
   void draw(Gfx *gfx, GBool printing) override;
@@ -817,7 +816,7 @@
 class AnnotMovie: public Annot {
  public:
   AnnotMovie(PDFDoc *docA, PDFRectangle *rect, Movie *movieA);
-  AnnotMovie(PDFDoc *docA, Dict *dict, Object *obj);
+  AnnotMovie(PDFDoc *docA, Object *dictObject, Object *obj);
   ~AnnotMovie();
 
   void draw(Gfx *gfx, GBool printing) override;
@@ -841,7 +840,7 @@
  public:
 
   AnnotScreen(PDFDoc *docA, PDFRectangle *rect);
-  AnnotScreen(PDFDoc *docA, Dict *dict, Object *obj);
+  AnnotScreen(PDFDoc *docA, Object *dictObject, Object *obj);
   ~AnnotScreen();
 
   GooString* getTitle() { return title; }
@@ -877,7 +876,7 @@
   };
 
   AnnotLink(PDFDoc *docA, PDFRectangle *rect);
-  AnnotLink(PDFDoc *docA, Dict *dict, Object *obj);
+  AnnotLink(PDFDoc *docA, Object *dictObject, Object *obj);
   ~AnnotLink();
 
   void draw(Gfx *gfx, GBool printing) override;
@@ -919,11 +918,11 @@
   };
 
   AnnotFreeText(PDFDoc *docA, PDFRectangle *rect, GooString *da);
-  AnnotFreeText(PDFDoc *docA, Dict *dict, Object *obj);
+  AnnotFreeText(PDFDoc *docA, Object *dictObject, Object *obj);
   ~AnnotFreeText();
 
   void draw(Gfx *gfx, GBool printing) override;
-  Object *getAppearanceResDict(Object *dest) override;
+  Object getAppearanceResDict() override;
   void setContents(GooString *new_content) override;
 
   void setAppearanceString(GooString *new_string);
@@ -983,11 +982,11 @@
   };
 
   AnnotLine(PDFDoc *docA, PDFRectangle *rect);
-  AnnotLine(PDFDoc *docA, Dict *dict, Object *obj);
+  AnnotLine(PDFDoc *docA, Object *dictObject, Object *obj);
   ~AnnotLine();
 
   void draw(Gfx *gfx, GBool printing) override;
-  Object *getAppearanceResDict(Object *dest) override;
+  Object getAppearanceResDict() override;
   void setContents(GooString *new_content) override;
 
   void setVertices(double x1, double y1, double x2, double y2);
@@ -1049,7 +1048,7 @@
 public:
 
   AnnotTextMarkup(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType);
-  AnnotTextMarkup(PDFDoc *docA, Dict *dict, Object *obj);
+  AnnotTextMarkup(PDFDoc *docA, Object *dictObject, Object *obj);
   ~AnnotTextMarkup();
 
   void draw(Gfx *gfx, GBool printing) override;
@@ -1076,7 +1075,7 @@
 public:
 
   AnnotStamp(PDFDoc *docA, PDFRectangle *rect);
-  AnnotStamp(PDFDoc *docA, Dict *dict, Object *obj);
+  AnnotStamp(PDFDoc *docA, Object *dictObject, Object *obj);
   ~AnnotStamp();
 
   void setIcon(GooString *new_icon);
@@ -1099,7 +1098,7 @@
 public:
 
   AnnotGeometry(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType);
-  AnnotGeometry(PDFDoc *docA, Dict *dict, Object *obj);
+  AnnotGeometry(PDFDoc *docA, Object *dictObject, Object *obj);
   ~AnnotGeometry();
 
   void draw(Gfx *gfx, GBool printing) override;
@@ -1135,7 +1134,7 @@
   };
 
   AnnotPolygon(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType);
-  AnnotPolygon(PDFDoc *docA, Dict *dict, Object *obj);
+  AnnotPolygon(PDFDoc *docA, Object *dictObject, Object *obj);
   ~AnnotPolygon();
 
   void draw(Gfx *gfx, GBool printing) override;
@@ -1185,7 +1184,7 @@
   };
 
   AnnotCaret(PDFDoc *docA, PDFRectangle *rect);
-  AnnotCaret(PDFDoc *docA, Dict *dict, Object *obj);
+  AnnotCaret(PDFDoc *docA, Object *dictObject, Object *obj);
   ~AnnotCaret();
 
   void setSymbol(AnnotCaretSymbol new_symbol);
@@ -1210,7 +1209,7 @@
 public:
 
   AnnotInk(PDFDoc *docA, PDFRectangle *rect);
-  AnnotInk(PDFDoc *docA, Dict *dict, Object *obj);
+  AnnotInk(PDFDoc *docA, Object *dictObject, Object *obj);
   ~AnnotInk();
 
   void draw(Gfx *gfx, GBool printing) override;
@@ -1245,7 +1244,7 @@
 public:
 
   AnnotFileAttachment(PDFDoc *docA, PDFRectangle *rect, GooString *filename);
-  AnnotFileAttachment(PDFDoc *docA, Dict *dict, Object *obj);
+  AnnotFileAttachment(PDFDoc *docA, Object *dictObject, Object *obj);
   ~AnnotFileAttachment();
 
   void draw(Gfx *gfx, GBool printing) override;
@@ -1273,7 +1272,7 @@
 public:
 
   AnnotSound(PDFDoc *docA, PDFRectangle *rect, Sound *soundA);
-  AnnotSound(PDFDoc *docA, Dict *dict, Object *obj);
+  AnnotSound(PDFDoc *docA, Object *dictObject, Object *obj);
   ~AnnotSound();
 
   void draw(Gfx *gfx, GBool printing) override;
@@ -1307,8 +1306,8 @@
     highlightModePush     // P,T
   };
 
-  AnnotWidget(PDFDoc *docA, Dict *dict, Object *obj);
-  AnnotWidget(PDFDoc *docA, Dict *dict, Object *obj, FormField *fieldA);
+  AnnotWidget(PDFDoc *docA, Object *dictObject, Object *obj);
+  AnnotWidget(PDFDoc *docA, Object *dictObject, Object *obj, FormField *fieldA);
   ~AnnotWidget();
 
   void draw(Gfx *gfx, GBool printing) override;
@@ -1398,7 +1397,7 @@
 public:
 
   Annot3D(PDFDoc *docA, PDFRectangle *rect);
-  Annot3D(PDFDoc *docA, Dict *dict, Object *obj);
+  Annot3D(PDFDoc *docA, Object *dictObject, Object *obj);
   ~Annot3D();
 
   // getters
@@ -1560,7 +1559,7 @@
   };
 
   AnnotRichMedia(PDFDoc *docA, PDFRectangle *rect);
-  AnnotRichMedia(PDFDoc *docA, Dict *dict, Object *obj);
+  AnnotRichMedia(PDFDoc *docA, Object *dictObject, Object *obj);
   ~AnnotRichMedia();
 
   Content* getContent() const;
@@ -1597,7 +1596,7 @@
   GBool removeAnnot(Annot *annot);
 
 private:
-  Annot* createAnnot(Dict* dict, Object *obj);
+  Annot* createAnnot(Object* dictObject, Object *obj);
   Annot *findAnnot(Ref *ref);
 
   PDFDoc *doc;
diff --git a/poppler/Array.cc b/poppler/Array.cc
index 230c328..c2c4040 100644
--- a/poppler/Array.cc
+++ b/poppler/Array.cc
@@ -16,7 +16,7 @@
 // Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
 // Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
-// Copyright (C) 2013 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2013, 2017 Albert Astals Cid <aacid@kde.org>
 //
 // 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
@@ -65,14 +65,13 @@
 #endif
 }
 
-Object *Array::copy(XRef *xrefA, Object *obj) {
+Object Array::copy(XRef *xrefA) {
   arrayLocker();
-  obj->initArray(xrefA);
+  Array *a = new Array(xrefA);
   for (int i = 0; i < length; ++i) {
-    Object obj1;
-    obj->arrayAdd(elems[i].copy(&obj1));
+    a->add(elems[i].copy());
   }
-  return obj;
+  return Object(a);
 }
 
 int Array::incRef() {
@@ -87,7 +86,7 @@
   return ref;
 }
 
-void Array::add(Object *elem) {
+void Array::add(Object &&elem) {
   arrayLocker();
   if (length == size) {
     if (length == 0) {
@@ -97,7 +96,8 @@
     }
     elems = (Object *)greallocn(elems, size, sizeof(Object));
   }
-  elems[length] = *elem;
+  elems[length].initNullAfterMalloc();
+  elems[length] = std::move(elem);
   ++length;
 }
 
@@ -114,39 +114,36 @@
   memmove( elems + i, elems + i + 1, sizeof(elems[0]) * (length - i) );
 }
 
-Object *Array::get(int i, Object *obj, int recursion) {
+Object Array::get(int i, int recursion) {
   if (i < 0 || i >= length) {
 #ifdef DEBUG_MEM
     abort();
 #else
-    return obj->initNull();
+    return Object(objNull);
 #endif
   }
-  return elems[i].fetch(xref, obj, recursion);
+  return elems[i].fetch(xref, recursion);
 }
 
-Object *Array::getNF(int i, Object *obj) {
+Object Array::getNF(int i) {
   if (i < 0 || i >= length) {
 #ifdef DEBUG_MEM
     abort();
 #else
-    return obj->initNull();
+    return Object(objNull);
 #endif
   }
-  return elems[i].copy(obj);
+  return elems[i].copy();
 }
 
 GBool Array::getString(int i, GooString *string)
 {
-  Object obj;
-
-  if (getNF(i, &obj)->isString()) {
+  Object obj = getNF(i);
+  if (obj.isString()) {
     string->clear();
     string->append(obj.getString());
-    obj.free();
     return gTrue;
   } else {
-    obj.free();
     return gFalse;
   }
 }
diff --git a/poppler/Array.h b/poppler/Array.h
index e78e399..8043c83 100644
--- a/poppler/Array.h
+++ b/poppler/Array.h
@@ -16,6 +16,7 @@
 // Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
 // Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2017 Albert Astals Cid <aacid@kde.org>
 //
 // 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
@@ -48,28 +49,30 @@
   // Destructor.
   ~Array();
 
-  // Reference counting.
-  int incRef();
-  int decRef();
-
   // Get number of elements.
   int getLength() { return length; }
 
   // Copy array with new xref
-  Object *copy(XRef *xrefA, Object *obj);
+  Object copy(XRef *xrefA);
 
-  // Add an element.
-  void add(Object *elem);
+  // Add an element
+  // elem becomes a dead object after this call
+  void add(Object &&elem);
 
   // Remove an element by position
   void remove(int i);
 
   // Accessors.
-  Object *get(int i, Object *obj, int resursion = 0);
-  Object *getNF(int i, Object *obj);
+  Object get(int i, int resursion = 0);
+  Object getNF(int i);
   GBool getString(int i, GooString *string);
 
 private:
+  friend class Object; // for incRef/decRef
+
+  // Reference counting.
+  int incRef();
+  int decRef();
 
   XRef *xref;			// the xref table for this PDF file
   Object *elems;		// array of elements
diff --git a/poppler/CMap.cc b/poppler/CMap.cc
index 6731ab5..5ed8565 100644
--- a/poppler/CMap.cc
+++ b/poppler/CMap.cc
@@ -14,7 +14,7 @@
 // under GPL version 2 or later
 //
 // Copyright (C) 2008 Koji Otani <sho@bbr.jp>
-// Copyright (C) 2008, 2009 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2008, 2009, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2013 Fabio D'Urso <fabiodurso@hotmail.it>
 //
 // To see a description of the changes please see the Changelog file that
@@ -116,15 +116,11 @@
 }
 
 CMap *CMap::parse(CMapCache *cache, GooString *collectionA, Stream *str) {
-  Object obj1;
-  CMap *cMap;
-
-  cMap = new CMap(collectionA->copy(), NULL);
-
-  if (!str->getDict()->lookup("UseCMap", &obj1)->isNull()) {
+  CMap *cMap = new CMap(collectionA->copy(), NULL);
+  Object obj1 = str->getDict()->lookup("UseCMap");
+  if (!obj1.isNull()) {
     cMap->useCMap(cache, &obj1);
   }
-  obj1.free();
 
   str->reset();
   cMap->parse2(cache, &getCharFromStream, str);
diff --git a/poppler/CairoFontEngine.cc b/poppler/CairoFontEngine.cc
index 6676f89..b56d100 100644
--- a/poppler/CairoFontEngine.cc
+++ b/poppler/CairoFontEngine.cc
@@ -17,7 +17,7 @@
 // Copyright (C) 2005-2007 Jeff Muizelaar <jeff@infidigm.net>
 // Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
 // Copyright (C) 2005 Martin Kretzschmar <martink@gnome.org>
-// Copyright (C) 2005, 2009, 2012, 2013, 2015 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2005, 2009, 2012, 2013, 2015, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2006, 2007, 2010, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
 // Copyright (C) 2007 Koji Otani <sho@bbr.jp>
 // Copyright (C) 2008, 2009 Chris Wilson <chris@chris-wilson.co.uk>
@@ -708,7 +708,8 @@
   output_dev->startDoc(info->doc, info->fontEngine);
   output_dev->startPage (1, gfx->getState(), gfx->getXRef());
   output_dev->setInType3Char(gTrue);
-  gfx->display(charProcs->getVal(glyph, &charProc));
+  charProc = charProcs->getVal(glyph);
+  gfx->display(&charProc);
 
   output_dev->getType3GlyphWidth (&wx, &wy);
   cairo_matrix_transform_distance (&matrix, &wx, &wy);
@@ -727,7 +728,6 @@
 
   delete gfx;
   delete output_dev;
-  charProc.free();
 
   return CAIRO_STATUS_SUCCESS;
 }
diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc
index 2946c92..9a2e053 100644
--- a/poppler/CairoOutputDev.cc
+++ b/poppler/CairoOutputDev.cc
@@ -16,7 +16,7 @@
 //
 // Copyright (C) 2005-2008 Jeff Muizelaar <jeff@infidigm.net>
 // Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
-// Copyright (C) 2005, 2009, 2012 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2005, 2009, 2012, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2005 Nickolay V. Shmyrev <nshmyrev@yandex.ru>
 // Copyright (C) 2006-2011, 2013, 2014 Carlos Garcia Campos <carlosgc@gnome.org>
 // Copyright (C) 2008 Carl Worth <cworth@cworth.org>
@@ -2956,9 +2956,8 @@
       return;
   }
 
-  str->getDict()->lookup("ColorSpace", &obj);
+  obj = str->getDict()->lookup("ColorSpace");
   colorSpace = GfxColorSpace::parse(NULL, &obj, this, state);
-  obj.free();
 
   // colorspace in stream dict may be different from colorspace in jpx
   // data
diff --git a/poppler/Catalog.cc b/poppler/Catalog.cc
index 0e37c84..6c820c6 100644
--- a/poppler/Catalog.cc
+++ b/poppler/Catalog.cc
@@ -14,7 +14,7 @@
 // under GPL version 2 or later
 //
 // Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
-// Copyright (C) 2005-2013, 2015 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2005-2013, 2015, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2005 Jeff Muizelaar <jrmuizel@nit.ca>
 // Copyright (C) 2005 Jonathan Blandford <jrb@redhat.com>
 // Copyright (C) 2005 Marco Pesenti Gritti <mpg@redhat.com>
@@ -74,10 +74,6 @@
 //------------------------------------------------------------------------
 
 Catalog::Catalog(PDFDoc *docA) {
-  Object catDict, pagesDict, pagesDictRef;
-  Object obj, obj2;
-  Object optContentProps;
-
 #if MULTITHREADED
   gInitMutex(&mutex);
 #endif
@@ -107,44 +103,39 @@
   lastCachedPage = 0;
   markInfo = markInfoNull;
 
-  xref->getCatalog(&catDict);
+  Object catDict = xref->getCatalog();
   if (!catDict.isDict()) {
     error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
-    goto err1;
+    ok = gFalse;
+    return;
   }
   // get the AcroForm dictionary
-  catDict.dictLookup("AcroForm", &acroForm);
+  acroForm = catDict.dictLookup("AcroForm");
 
   // read base URI
-  if (catDict.dictLookup("URI", &obj)->isDict()) {
-    if (obj.dictLookup("Base", &obj2)->isString()) {
+  Object obj = catDict.dictLookup("URI");
+  if (obj.isDict()) {
+    Object obj2 = obj.dictLookup("Base");
+    if (obj2.isString()) {
       baseURI = obj2.getString()->copy();
     }
-    obj2.free();
   }
-  obj.free();
 
   // get the Optional Content dictionary
-  if (catDict.dictLookup("OCProperties", &optContentProps)->isDict()) {
+  Object optContentProps = catDict.dictLookup("OCProperties");
+  if (optContentProps.isDict()) {
     optContent = new OCGs(&optContentProps, xref);
     if (!optContent->isOk ()) {
       delete optContent;
       optContent = NULL;
     }
   }
-  optContentProps.free();
 
   // actions
-  catDict.dictLookupNF("AA", &additionalActions);
+  additionalActions = catDict.dictLookupNF("AA");
 
   // get the ViewerPreferences dictionary
-  catDict.dictLookup("ViewerPreferences", &viewerPreferences);
-  catDict.free();
-  return;
-
- err1:
-  catDict.free();
-  ok = gFalse;
+  viewerPreferences = catDict.dictLookup("ViewerPreferences");
 }
 
 Catalog::~Catalog() {
@@ -157,15 +148,7 @@
     delete attrsList;
   }
   delete pagesRefList;
-  if (pagesList) {
-    std::vector<Dict *>::iterator it;
-    for (it = pagesList->begin() ; it != pagesList->end(); ++it ) {
-      if (!(*it)->decRef()) {
-         delete *it;
-      }
-    }
-    delete pagesList;
-  }
+  delete pagesList;
   if (pages) {
     for (int i = 0; i < pagesSize; ++i) {
       if (pages[i]) {
@@ -175,8 +158,6 @@
     gfree(pages);
   }
   gfree(pageRefs);
-  names.free();
-  dests.free();
   delete destNameTree;
   delete embeddedFileNameTree;
   delete jsNameTree;
@@ -188,45 +169,32 @@
   delete optContent;
   delete viewerPrefs;
   delete structTreeRoot;
-  metadata.free();
-  outline.free();
-  acroForm.free();
-  viewerPreferences.free();
-  additionalActions.free();
 #if MULTITHREADED
   gDestroyMutex(&mutex);
 #endif
 }
 
 GooString *Catalog::readMetadata() {
-  GooString *s;
-  Dict *dict;
-  Object obj;
-
   catalogLocker();
   if (metadata.isNone()) {
-    Object catDict;
-
-    xref->getCatalog(&catDict);
+    Object catDict = xref->getCatalog();
     if (catDict.isDict()) {
-      catDict.dictLookup("Metadata", &metadata);
+      metadata = catDict.dictLookup("Metadata");
     } else {
       error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
-      metadata.initNull();
+      metadata.setToNull();
     }
-    catDict.free();
   }
 
   if (!metadata.isStream()) {
-    return NULL;
+    return nullptr;
   }
-  dict = metadata.streamGetDict();
-  if (!dict->lookup("Subtype", &obj)->isName("XML")) {
+  Object obj = metadata.streamGetDict()->lookup("Subtype");
+  if (!obj.isName("XML")) {
     error(errSyntaxWarning, -1, "Unknown Metadata type: '{0:s}'",
 	  obj.isName() ? obj.getName() : "???");
   }
-  obj.free();
-  s = new GooString();
+  GooString *s = new GooString();
   metadata.getStream()->fillGooString(s);
   metadata.streamClose();
   return s;
@@ -262,47 +230,32 @@
 
 GBool Catalog::cachePageTree(int page)
 {
-  Dict *pagesDict;
-
   if (pagesList == NULL) {
 
-    Object catDict;
     Ref pagesRef;
 
-    xref->getCatalog(&catDict);
+    Object catDict = xref->getCatalog();
 
     if (catDict.isDict()) {
-      Object pagesDictRef;
-      if (catDict.dictLookupNF("Pages", &pagesDictRef)->isRef() &&
+      Object pagesDictRef = catDict.dictLookupNF("Pages");
+      if (pagesDictRef.isRef() &&
           pagesDictRef.getRefNum() >= 0 &&
           pagesDictRef.getRefNum() < xref->getNumObjects()) {
         pagesRef = pagesDictRef.getRef();
-        pagesDictRef.free();
       } else {
         error(errSyntaxError, -1, "Catalog dictionary does not contain a valid \"Pages\" entry");
-        pagesDictRef.free();
-        catDict.free();
         return gFalse;
       }
     } else {
       error(errSyntaxError, -1, "Could not find catalog dictionary");
-      catDict.free();
       return gFalse;
     }
 
-    Object obj;
-    catDict.dictLookup("Pages", &obj);
-    catDict.free();
+    Object obj = catDict.dictLookup("Pages");
     // This should really be isDict("Pages"), but I've seen at least one
     // PDF file where the /Type entry is missing.
-    if (obj.isDict()) {
-      obj.getDict()->incRef();
-      pagesDict = obj.getDict();
-      obj.free();
-    }
-    else {
+    if (!obj.isDict()) {
       error(errSyntaxError, -1, "Top-level pages object is wrong type ({0:s})", obj.getTypeName());
-      obj.free();
       return gFalse;
     }
 
@@ -311,7 +264,6 @@
     pageRefs = (Ref *)gmallocn_checkoverflow(pagesSize, sizeof(Ref));
     if (pages == NULL || pageRefs == NULL ) {
       error(errSyntaxError, -1, "Cannot allocate page cache");
-      pagesDict->decRef();
       pagesSize = 0;
       return gFalse;
     }
@@ -321,12 +273,12 @@
       pageRefs[i].gen = -1;
     }
 
-    pagesList = new std::vector<Dict *>();
-    pagesList->push_back(pagesDict);
+    attrsList = new std::vector<PageAttrs *>();
+    attrsList->push_back(new PageAttrs(NULL, obj.getDict()));
+    pagesList = new std::vector<Object>();
+    pagesList->push_back(std::move(obj));
     pagesRefList = new std::vector<Ref>();
     pagesRefList->push_back(pagesRef);
-    attrsList = new std::vector<PageAttrs *>();
-    attrsList->push_back(new PageAttrs(NULL, pagesDict));
     kidsIdxList = new std::vector<int>();
     kidsIdxList->push_back(0);
     lastCachedPage = 0;
@@ -339,38 +291,29 @@
 
     if (pagesList->empty()) return gFalse;
 
-    pagesDict = pagesList->back();
-    Object kids;
-    pagesDict->lookup("Kids", &kids);
+    Object pagesDict = pagesList->back().copy();
+    Object kids = pagesDict.dictLookup("Kids");
     if (!kids.isArray()) {
       error(errSyntaxError, -1, "Kids object (page {0:d}) is wrong type ({1:s})",
             lastCachedPage+1, kids.getTypeName());
-      kids.free();
       return gFalse;
     }
 
     int kidsIdx = kidsIdxList->back();
     if (kidsIdx >= kids.arrayGetLength()) {
-       if (!pagesList->back()->decRef()) {
-         delete pagesList->back();
-       }
        pagesList->pop_back();
        pagesRefList->pop_back();
        delete attrsList->back();
        attrsList->pop_back();
        kidsIdxList->pop_back();
        if (!kidsIdxList->empty()) kidsIdxList->back()++;
-       kids.free();
        continue;
     }
 
-    Object kidRef;
-    kids.arrayGetNF(kidsIdx, &kidRef);
+    Object kidRef = kids.arrayGetNF(kidsIdx);
     if (!kidRef.isRef()) {
       error(errSyntaxError, -1, "Kid object (page {0:d}) is not an indirect reference ({1:s})",
             lastCachedPage+1, kidRef.getTypeName());
-      kidRef.free();
-      kids.free();
       return gFalse;
     }
 
@@ -383,31 +326,23 @@
     }
     if (loop) {
       error(errSyntaxError, -1, "Loop in Pages tree");
-      kidRef.free();
-      kids.free();
       kidsIdxList->back()++;
       continue;
     }
 
-    Object kid;
-    kids.arrayGet(kidsIdx, &kid);
-    kids.free();
+    Object kid = kids.arrayGet(kidsIdx);
     if (kid.isDict("Page") || (kid.isDict() && !kid.getDict()->hasKey("Kids"))) {
       PageAttrs *attrs = new PageAttrs(attrsList->back(), kid.getDict());
-      Page *p = new Page(doc, lastCachedPage+1, kid.getDict(),
+      Page *p = new Page(doc, lastCachedPage+1, &kid,
                      kidRef.getRef(), attrs, form);
       if (!p->isOk()) {
         error(errSyntaxError, -1, "Failed to create page (page {0:d})", lastCachedPage+1);
         delete p;
-        kidRef.free();
-        kid.free();
         return gFalse;
       }
 
       if (lastCachedPage >= numPages) {
         error(errSyntaxError, -1, "Page count in top-level pages object is incorrect");
-        kidRef.free();
-        kid.free();
         return gFalse;
       }
 
@@ -423,17 +358,13 @@
     } else if (kid.isDict()) {
       attrsList->push_back(new PageAttrs(attrsList->back(), kid.getDict()));
       pagesRefList->push_back(kidRef.getRef());
-      kid.getDict()->incRef();
-      pagesList->push_back(kid.getDict());
+      pagesList->push_back(std::move(kid));
       kidsIdxList->push_back(0);
     } else {
       error(errSyntaxError, -1, "Kid object (page {0:d}) is wrong type ({1:s})",
             lastCachedPage+1, kid.getTypeName());
       kidsIdxList->back()++;
     }
-    kidRef.free();
-    kid.free();
-
   }
 
   return gFalse;
@@ -451,48 +382,28 @@
 }
 
 LinkDest *Catalog::findDest(GooString *name) {
-  LinkDest *dest;
-  Object obj1;
-  GBool found;
-
   // try named destination dictionary then name tree
-  found = gFalse;
   if (getDests()->isDict()) {
-    if (!getDests()->dictLookup(name->getCString(), &obj1)->isNull())
-      found = gTrue;
-    else
-      obj1.free();
+    Object obj1 = getDests()->dictLookup(name->getCString());
+    return createLinkDest(&obj1);
   }
-  if (!found) {
-    catalogLocker();
-    if (getDestNameTree()->lookup(name, &obj1))
-      found = gTrue;
-    else
-      obj1.free();
-  }
-  if (!found)
-    return NULL;
 
-  dest = createLinkDest(&obj1);
-  obj1.free();
-
-  return dest;
+  catalogLocker();
+  Object obj2 = getDestNameTree()->lookup(name);
+  return createLinkDest(&obj2);
 }
 
 LinkDest *Catalog::createLinkDest(Object *obj)
 {
-  LinkDest *dest;
-  Object obj2;
-
-  dest = NULL;
+  LinkDest *dest = nullptr;
   if (obj->isArray()) {
     dest = new LinkDest(obj->getArray());
   } else if (obj->isDict()) {
-    if (obj->dictLookup("D", &obj2)->isArray())
+    Object obj2 = obj->dictLookup("D");
+    if (obj2.isArray())
       dest = new LinkDest(obj2.getArray());
     else
       error(errSyntaxWarning, -1, "Bad named destination value");
-    obj2.free();
   } else {
     error(errSyntaxWarning, -1, "Bad named destination value");
   }
@@ -528,46 +439,37 @@
 
 LinkDest *Catalog::getDestsDest(int i)
 {
-  LinkDest *dest;
-  Object *obj, obj1;
-
-  obj= getDests();
+  Object *obj = getDests();
   if (!obj->isDict()) {
     return NULL;
   }
-  obj->dictGetVal(i, &obj1);
-  dest = createLinkDest(&obj1);
-  obj1.free();
-
-  return dest;
+  Object obj1 = obj->dictGetVal(i);
+  return createLinkDest(&obj1);
 }
 
 LinkDest *Catalog::getDestNameTreeDest(int i)
 {
-  LinkDest *dest;
   Object obj;
 
   catalogLocker();
-  getDestNameTree()->getValue(i).fetch(xref, &obj);
-  dest = createLinkDest(&obj);
-  obj.free();
-
-  return dest;
+  Object *aux = getDestNameTree()->getValue(i);
+  if (aux) {
+    obj = aux->fetch(xref);
+  }
+  return createLinkDest(&obj);
 }
 
 FileSpec *Catalog::embeddedFile(int i)
 {
     Object efDict;
-    Object obj;
     catalogLocker();
-    obj = getEmbeddedFileNameTree()->getValue(i);
+    Object *obj = getEmbeddedFileNameTree()->getValue(i);
     FileSpec *embeddedFile = 0;
-    if (obj.isRef()) {
-      Object fsDict;
-      embeddedFile = new FileSpec(obj.fetch(xref, &fsDict));
-      fsDict.free();
-    } else if (obj.isDict()) {
-      embeddedFile = new FileSpec(&obj);
+    if (obj->isRef()) {
+      Object fsDict = obj->fetch(xref);
+      embeddedFile = new FileSpec(&fsDict);
+    } else if (obj->isDict()) {
+      embeddedFile = new FileSpec(obj);
     } else {
       Object null;
       embeddedFile = new FileSpec(&null);
@@ -581,26 +483,23 @@
   // getJSNameTree()->getValue(i) returns a shallow copy of the object so we
   // do not need to free it
   catalogLocker();
-  getJSNameTree()->getValue(i).fetch(xref, &obj);
+  Object *aux = getJSNameTree()->getValue(i);
+  if (aux) {
+    obj = aux->fetch(xref);
+  }
 
   if (!obj.isDict()) {
-    obj.free();
-    return 0;
+    return nullptr;
   }
-  Object obj2;
-  if (!obj.dictLookup("S", &obj2)->isName()) {
-    obj2.free();
-    obj.free();
-    return 0;
+  Object obj2 = obj.dictLookup("S");
+  if (!obj2.isName()) {
+    return nullptr;
   }
   if (strcmp(obj2.getName(), "JavaScript")) {
-    obj2.free();
-    obj.free();
-    return 0;
+    return nullptr;
   }
-  obj2.free();
-  obj.dictLookup("JS", &obj2);
-  GooString *js = 0;
+  obj2 = obj.dictLookup("JS");
+  GooString *js = nullptr;
   if (obj2.isString()) {
     js = new GooString(obj2.getString());
   }
@@ -609,8 +508,6 @@
     js = new GooString();
     stream->fillGooString(js);
   }
-  obj2.free();
-  obj.free();
   return js;
 }
 
@@ -619,18 +516,16 @@
   catalogLocker();
   if (pageMode == pageModeNull) {
 
-    Object catDict, obj;
-
     pageMode = pageModeNone;
 
-    xref->getCatalog(&catDict);
+    Object catDict = xref->getCatalog();
     if (!catDict.isDict()) {
       error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
-      catDict.free();
       return pageMode;
     }
 
-    if (catDict.dictLookup("PageMode", &obj)->isName()) {
+    Object obj = catDict.dictLookup("PageMode");
+    if (obj.isName()) {
       if (obj.isName("UseNone"))
         pageMode = pageModeNone;
       else if (obj.isName("UseOutlines"))
@@ -644,8 +539,6 @@
       else if (obj.isName("UseAttachments"))
         pageMode = pageModeAttach;
     }
-    obj.free();
-    catDict.free();
   }
   return pageMode;
 }
@@ -655,19 +548,17 @@
   catalogLocker();
   if (pageLayout == pageLayoutNull) {
 
-    Object catDict, obj;
-
     pageLayout = pageLayoutNone;
 
-    xref->getCatalog(&catDict);
+    Object catDict = xref->getCatalog();
     if (!catDict.isDict()) {
       error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
-      catDict.free();
       return pageLayout;
     }
 
     pageLayout = pageLayoutNone;
-    if (catDict.dictLookup("PageLayout", &obj)->isName()) {
+    Object obj = catDict.dictLookup("PageLayout");
+    if (obj.isName()) {
       if (obj.isName("SinglePage"))
         pageLayout = pageLayoutSinglePage;
       if (obj.isName("OneColumn"))
@@ -681,8 +572,6 @@
       if (obj.isName("TwoPageRight"))
         pageLayout = pageLayoutTwoPageRight;
     }
-    obj.free();
-    catDict.free();
   }
   return pageLayout;
 }
@@ -705,20 +594,19 @@
 }
 
 NameTree::Entry::Entry(Array *array, int index) {
-    if (!array->getString(index, &name) || !array->getNF(index + 1, &value)) {
-      Object aux;
-      array->get(index, &aux);
-      if (aux.isString() && array->getNF(index + 1, &value) )
-      {
-        name.append(aux.getString());
-      }
-      else
-        error(errSyntaxError, -1, "Invalid page tree");
+  if (!array->getString(index, &name)) {
+    Object aux = array->get(index);
+    if (aux.isString())
+    {
+      name.append(aux.getString());
     }
+    else
+      error(errSyntaxError, -1, "Invalid page tree");
+  }
+  value = array->getNF(index + 1);
 }
 
 NameTree::Entry::~Entry() {
-  value.free();
 }
 
 void NameTree::addEntry(Entry *entry)
@@ -753,33 +641,29 @@
 }
 
 void NameTree::parse(Object *tree) {
-  Object names;
-  Object kids, kid;
-  int i;
-
   if (!tree->isDict())
     return;
 
   // leaf node
-  if (tree->dictLookup("Names", &names)->isArray()) {
-    for (i = 0; i < names.arrayGetLength(); i += 2) {
+  Object names = tree->dictLookup("Names");
+  if (names.isArray()) {
+    for (int i = 0; i < names.arrayGetLength(); i += 2) {
       NameTree::Entry *entry;
 
       entry = new Entry(names.getArray(), i);
       addEntry(entry);
     }
   }
-  names.free();
 
   // root or intermediate node
-  if (tree->dictLookup("Kids", &kids)->isArray()) {
-    for (i = 0; i < kids.arrayGetLength(); ++i) {
-      if (kids.arrayGet(i, &kid)->isDict())
+  Object kids = tree->dictLookup("Kids");
+  if (kids.isArray()) {
+    for (int i = 0; i < kids.arrayGetLength(); ++i) {
+      Object kid = kids.arrayGet(i);
+      if (kid.isDict())
 	parse(&kid);
-      kid.free();
     }
   }
-  kids.free();
 }
 
 int NameTree::Entry::cmp(const void *voidKey, const void *voidEntry)
@@ -790,28 +674,26 @@
   return key->cmp(&entry->name);
 }
 
-GBool NameTree::lookup(GooString *name, Object *obj)
+Object NameTree::lookup(GooString *name)
 {
   Entry **entry;
 
   entry = (Entry **) bsearch(name, entries,
 			     length, sizeof(Entry *), Entry::cmp);
   if (entry != NULL) {
-    (*entry)->value.fetch(xref, obj);
-    return gTrue;
+    return (*entry)->value.fetch(xref);
   } else {
     error(errSyntaxError, -1, "failed to look up ({0:s})", name->getCString());
-    obj->initNull();
-    return gFalse;
+    return Object(objNull);
   }
 }
 
-Object NameTree::getValue(int index)
+Object *NameTree::getValue(int index)
 {
   if (index < length) {
-    return entries[index]->value;
+    return &entries[index]->value;
   } else {
-    return Object();
+    return nullptr;
   }
 }
 
@@ -866,39 +748,33 @@
   catalogLocker();
   if (numPages == -1)
   {
-    Object catDict, pagesDict, obj;
-
-    xref->getCatalog(&catDict);
+    Object catDict = xref->getCatalog();
     if (!catDict.isDict()) {
       error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
-      catDict.free();
       return 0;
     }
-    catDict.dictLookup("Pages", &pagesDict);
+    Object pagesDict = catDict.dictLookup("Pages");
 
     // This should really be isDict("Pages"), but I've seen at least one
     // PDF file where the /Type entry is missing.
     if (!pagesDict.isDict()) {
       error(errSyntaxError, -1, "Top-level pages object is wrong type ({0:s})",
           pagesDict.getTypeName());
-      pagesDict.free();
-      catDict.free();
       return 0;
     }
 
-    pagesDict.dictLookup("Count", &obj);
+    Object obj = pagesDict.dictLookup("Count");
     // some PDF files actually use real numbers here ("/Count 9.0")
     if (!obj.isNum()) {
       if (pagesDict.dictIs("Page")) {
-	Object pageRootRef;
-	catDict.dictLookupNF("Pages", &pageRootRef);
+	Object pageRootRef = catDict.dictLookupNF("Pages");
 
 	error(errSyntaxError, -1, "Pages top-level is a single Page. The document is malformed, trying to recover...");
 
 	Dict *pageDict = pagesDict.getDict();
 	if (pageRootRef.isRef()) {
 	  const Ref pageRef = pageRootRef.getRef();
-	  Page *p = new Page(doc, 1, pageDict, pageRef, new PageAttrs(NULL, pageDict), form);
+	  Page *p = new Page(doc, 1, &pagesDict, pageRef, new PageAttrs(NULL, pageDict), form);
 	  if (p->isOk()) {
 	    pages = (Page **)gmallocn(1, sizeof(Page *));
 	    pageRefs = (Ref *)gmallocn(1, sizeof(Ref));
@@ -936,10 +812,6 @@
       }
 
     }
-
-    catDict.free();
-    obj.free();
-    pagesDict.free();
   }
 
   return numPages;
@@ -949,21 +821,16 @@
 {
   catalogLocker();
   if (!pageLabelInfo) {
-    Object catDict;
-    Object obj;
-
-    xref->getCatalog(&catDict);
+    Object catDict = xref->getCatalog();
     if (!catDict.isDict()) {
       error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
-      catDict.free();
-      return NULL;
+      return nullptr;
     }
 
-    if (catDict.dictLookup("PageLabels", &obj)->isDict()) {
+    Object obj = catDict.dictLookup("PageLabels");
+    if (obj.isDict()) {
       pageLabelInfo = new PageLabelInfo(&obj, getNumPages());
     }
-    obj.free();
-    catDict.free();
   }
 
   return pageLabelInfo;
@@ -973,22 +840,16 @@
 {
   catalogLocker();
   if (!structTreeRoot) {
-    Object catalog;
-    Object root;
-
-    xref->getCatalog(&catalog);
+    Object catalog = xref->getCatalog();
     if (!catalog.isDict()) {
       error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catalog.getTypeName());
-      catalog.free();
       return NULL;
     }
 
-    if (catalog.dictLookup("StructTreeRoot", &root)->isDict("StructTreeRoot")) {
+    Object root = catalog.dictLookup("StructTreeRoot");
+    if (root.isDict("StructTreeRoot")) {
       structTreeRoot = new StructTreeRoot(doc, root.getDict());
     }
-
-    root.free();
-    catalog.free();
   }
   return structTreeRoot;
 }
@@ -998,41 +859,35 @@
   if (markInfo == markInfoNull) {
     markInfo = 0;
 
-    Object catDict;
     catalogLocker();
-    xref->getCatalog(&catDict);
+    Object catDict = xref->getCatalog();
 
     if (catDict.isDict()) {
-      Object markInfoDict;
-      catDict.dictLookup("MarkInfo", &markInfoDict);
+      Object markInfoDict = catDict.dictLookup("MarkInfo");
       if (markInfoDict.isDict()) {
-        Object value;
-
-        if (markInfoDict.dictLookup("Marked", &value)->isBool() && value.getBool())
+        Object value = markInfoDict.dictLookup("Marked");
+        if (value.isBool() && value.getBool())
           markInfo |= markInfoMarked;
         else if (!value.isNull())
           error(errSyntaxError, -1, "Marked object is wrong type ({0:s})", value.getTypeName());
-        value.free();
 
-        if (markInfoDict.dictLookup("Suspects", &value)->isBool() && value.getBool())
+        value = markInfoDict.dictLookup("Suspects");
+        if (value.isBool() && value.getBool())
           markInfo |= markInfoSuspects;
         else if (!value.isNull())
           error(errSyntaxError, -1, "Suspects object is wrong type ({0:s})", value.getTypeName());
-        value.free();
 
-        if (markInfoDict.dictLookup("UserProperties", &value)->isBool() && value.getBool())
+        value = markInfoDict.dictLookup("UserProperties");
+        if (value.isBool() && value.getBool())
           markInfo |= markInfoUserProperties;
         else if (!value.isNull())
           error(errSyntaxError, -1, "UserProperties object is wrong type ({0:s})", value.getTypeName());
-        value.free();
       } else if (!markInfoDict.isNull()) {
         error(errSyntaxError, -1, "MarkInfo object is wrong type ({0:s})", markInfoDict.getTypeName());
       }
-      markInfoDict.free();
     } else {
       error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
     }
-    catDict.free();
   }
   return markInfo;
 }
@@ -1042,16 +897,13 @@
   catalogLocker();
   if (outline.isNone())
   {
-     Object catDict;
-
-     xref->getCatalog(&catDict);
+     Object catDict = xref->getCatalog();
      if (catDict.isDict()) {
-       catDict.dictLookup("Outlines", &outline);
+       outline = catDict.dictLookup("Outlines");
      } else {
        error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
-       outline.initNull();
+       outline.setToNull();
      }
-     catDict.free();
   }
 
   return &outline;
@@ -1062,16 +914,13 @@
   catalogLocker();
   if (dests.isNone())
   {
-     Object catDict;
-
-     xref->getCatalog(&catDict);
+     Object catDict = xref->getCatalog();
      if (catDict.isDict()) {
-       catDict.dictLookup("Dests", &dests);
+       dests = catDict.dictLookup("Dests");
      } else {
        error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
-       dests.initNull();
+       dests.setToNull();
      }
-     catDict.free();
   }
 
   return &dests;
@@ -1083,13 +932,12 @@
   FormType res = NoForm;
 
   if (acroForm.isDict()) {
-    acroForm.dictLookup("XFA", &xfa);
+    xfa = acroForm.dictLookup("XFA");
     if (xfa.isStream() || xfa.isArray()) {
       res = XfaForm;
     } else {
       res = AcroForm;
     }
-    xfa.free();
   }
 
   return res;
@@ -1125,16 +973,13 @@
 {
   if (names.isNone())
   {
-     Object catDict;
-
-     xref->getCatalog(&catDict);
+     Object catDict = xref->getCatalog();
      if (catDict.isDict()) {
-       catDict.dictLookup("Names", &names);
+       names = catDict.dictLookup("Names");
      } else {
        error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
-       names.initNull();
+       names.setToNull();
      }
-     catDict.free();
   }
 
   return &names;
@@ -1147,11 +992,8 @@
     destNameTree = new NameTree();
 
     if (getNames()->isDict()) {
-       Object obj;
-
-       getNames()->dictLookup("Dests", &obj);
+       Object obj = getNames()->dictLookup("Dests");
        destNameTree->init(xref, &obj);
-       obj.free();
     }
 
   }
@@ -1166,11 +1008,8 @@
     embeddedFileNameTree = new NameTree();
 
     if (getNames()->isDict()) {
-       Object obj;
-
-       getNames()->dictLookup("EmbeddedFiles", &obj);
+       Object obj = getNames()->dictLookup("EmbeddedFiles");
        embeddedFileNameTree->init(xref, &obj);
-       obj.free();
     }
 
   }
@@ -1185,11 +1024,8 @@
     jsNameTree = new NameTree();
 
     if (getNames()->isDict()) {
-       Object obj;
-
-       getNames()->dictLookup("JavaScript", &obj);
+       Object obj = getNames()->dictLookup("JavaScript");
        jsNameTree->init(xref, &obj);
-       obj.free();
     }
 
   }
@@ -1198,24 +1034,18 @@
 }
 
 LinkAction* Catalog::getAdditionalAction(DocumentAdditionalActionsType type) {
-  Object additionalActionsObject;
-  LinkAction *linkAction = NULL;
-
-  if (additionalActions.fetch(doc->getXRef(), &additionalActionsObject)->isDict()) {
+  LinkAction *linkAction = nullptr;
+  Object additionalActionsObject = additionalActions.fetch(doc->getXRef());
+  if (additionalActionsObject.isDict()) {
     const char *key = (type == actionCloseDocument ?       "WC" :
                        type == actionSaveDocumentStart ?   "WS" :
                        type == actionSaveDocumentFinish ?  "DS" :
                        type == actionPrintDocumentStart ?  "WP" :
                        type == actionPrintDocumentFinish ? "DP" : NULL);
 
-    Object actionObject;
-
-    if (additionalActionsObject.dictLookup(key, &actionObject)->isDict())
+    Object actionObject = additionalActionsObject.dictLookup(key);
+    if (actionObject.isDict())
       linkAction = LinkAction::parseAction(&actionObject, doc->getCatalog()->getBaseURI());
-    actionObject.free();
   }
-
-  additionalActionsObject.free();
-
   return linkAction;
 }
diff --git a/poppler/Catalog.h b/poppler/Catalog.h
index 81b0e12..c8b501a 100644
--- a/poppler/Catalog.h
+++ b/poppler/Catalog.h
@@ -14,7 +14,7 @@
 // under GPL version 2 or later
 //
 // Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
-// Copyright (C) 2005, 2007, 2009-2011, 2013 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2005, 2007, 2009-2011, 2013, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2005 Jonathan Blandford <jrb@redhat.com>
 // Copyright (C) 2005, 2006, 2008 Brad Hards <bradh@frogmouth.net>
 // Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org>
@@ -69,10 +69,10 @@
   NameTree();
   ~NameTree();
   void init(XRef *xref, Object *tree);
-  GBool lookup(GooString *name, Object *obj);
+  Object lookup(GooString *name);
   int numEntries() { return length; };
-  // iterator accessor, note it returns a shallow copy, do not free the object
-  Object getValue(int i);
+  // iterator accessor, note it returns a pointer to the internal object, do not free nor delete it
+  Object *getValue(int i);
   GooString *getName(int i);
 
 private:
@@ -248,7 +248,7 @@
   Page **pages;			// array of pages
   Ref *pageRefs;		// object ID for each page
   int lastCachedPage;
-  std::vector<Dict *> *pagesList;
+  std::vector<Object> *pagesList;
   std::vector<Ref> *pagesRefList;
   std::vector<PageAttrs *> *attrsList;
   std::vector<int> *kidsIdxList;
diff --git a/poppler/CurlPDFDocBuilder.cc b/poppler/CurlPDFDocBuilder.cc
index 5b02b14..91d4c30 100644
--- a/poppler/CurlPDFDocBuilder.cc
+++ b/poppler/CurlPDFDocBuilder.cc
@@ -24,14 +24,11 @@
 CurlPDFDocBuilder::buildPDFDoc(const GooString &uri,
         GooString *ownerPassword, GooString *userPassword, void *guiDataA)
 {
-    Object obj;
-
     CachedFile *cachedFile = new CachedFile(
         new CurlCachedFileLoader(), uri.copy());
 
-    obj.initNull();
     BaseStream *str = new CachedFileStream(
-         cachedFile, 0, gFalse, cachedFile->getLength(), &obj);
+         cachedFile, 0, gFalse, cachedFile->getLength(), Object(objNull));
 
     return new PDFDoc(str, ownerPassword, userPassword, guiDataA);
 }
diff --git a/poppler/DCTStream.cc b/poppler/DCTStream.cc
index bfdb0ea..b3e1303 100644
--- a/poppler/DCTStream.cc
+++ b/poppler/DCTStream.cc
@@ -5,7 +5,7 @@
 // This file is licensed under the GPLv2 or later
 //
 // Copyright 2005 Jeff Muizelaar <jeff@infidigm.net>
-// Copyright 2005-2010, 2012 Albert Astals Cid <aacid@kde.org>
+// Copyright 2005-2010, 2012, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright 2009 Ryszard Trojnacki <rysiek@menel.com>
 // Copyright 2010 Carlos Garcia Campos <carlosgc@gnome.org>
 // Copyright 2011 Daiki Ueno <ueno@unixuser.org>
@@ -60,18 +60,14 @@
 {
 }
 
-DCTStream::DCTStream(Stream *strA, int colorXformA, Object *dict, int recursion) :
+DCTStream::DCTStream(Stream *strA, int colorXformA, Dict *dict, int recursion) :
   FilterStream(strA) {
   colorXform = colorXformA;
   if (dict != NULL) {
-    Object obj;
-
-    dict->dictLookup("Width", &obj, recursion);
+    Object obj = dict->lookup("Width", recursion);
     err.width = (obj.isInt() && obj.getInt() <= JPEG_MAX_DIMENSION) ? obj.getInt() : 0;
-    obj.free();
-    dict->dictLookup("Height", &obj, recursion);
+    obj = dict->lookup("Height", recursion);
     err.height = (obj.isInt() && obj.getInt() <= JPEG_MAX_DIMENSION) ? obj.getInt() : 0;
-    obj.free();
   } else
     err.height = err.width = 0;
   init();
diff --git a/poppler/DCTStream.h b/poppler/DCTStream.h
index cfa0663..00e0484 100644
--- a/poppler/DCTStream.h
+++ b/poppler/DCTStream.h
@@ -6,7 +6,7 @@
 //
 // Copyright 2005 Jeff Muizelaar <jeff@infidigm.net>
 // Copyright 2005 Martin Kretzschmar <martink@gnome.org>
-// Copyright 2005-2007, 2009-2011 Albert Astals Cid <aacid@kde.org>
+// Copyright 2005-2007, 2009-2011, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright 2010 Carlos Garcia Campos <carlosgc@gnome.org>
 // Copyright 2011 Daiki Ueno <ueno@unixuser.org>
 // Copyright 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
@@ -64,7 +64,7 @@
 class DCTStream: public FilterStream {
 public:
 
-  DCTStream(Stream *strA, int colorXformA, Object *dict, int recursion);
+  DCTStream(Stream *strA, int colorXformA, Dict *dict, int recursion);
   ~DCTStream();
   StreamKind getKind() override { return strDCT; }
   void reset() override;
diff --git a/poppler/Dict.cc b/poppler/Dict.cc
index c2a94f4..5c231d1 100644
--- a/poppler/Dict.cc
+++ b/poppler/Dict.cc
@@ -16,7 +16,7 @@
 // Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
 // Copyright (C) 2006 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
 // Copyright (C) 2007-2008 Julien Rebetez <julienr@svn.gnome.org>
-// Copyright (C) 2008, 2010, 2013, 2014 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2008, 2010, 2013, 2014, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2010 Paweł Wiejacha <pawel.wiejacha@gmail.com>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
 // Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
@@ -98,7 +98,8 @@
   entries = (DictEntry *)gmallocn(size, sizeof(DictEntry));
   for (int i=0; i<length; i++) {
     entries[i].key = copyString(dictA->entries[i].key);
-    dictA->entries[i].val.copy(&entries[i].val);
+    entries[i].val.initNullAfterMalloc();
+    entries[i].val = dictA->entries[i].val.copy();
   }
 }
 
@@ -108,12 +109,8 @@
   dictA->xref = xrefA;
   for (int i=0; i<length; i++) {
     if (dictA->entries[i].val.getType() == objDict) {
-       Dict *dict = dictA->entries[i].val.getDict();
-       Object obj;
-       obj.initDict(dict->copy(xrefA));
-       dictA->entries[i].val.free();
-       dictA->entries[i].val = obj;
-       obj.free();
+       Dict *copy = dictA->entries[i].val.getDict()->copy(xrefA);
+       dictA->entries[i].val = Object(copy);
     }
   }
   return dictA;
@@ -144,7 +141,7 @@
   return ref;
 }
 
-void Dict::add(char *key, Object *val) {
+void Dict::add(char *key, Object &&val) {
   dictLocker();
   if (sorted) {
     // We use add on very few occasions so
@@ -161,7 +158,8 @@
     entries = (DictEntry *)greallocn(entries, size, sizeof(DictEntry));
   }
   entries[length].key = key;
-  entries[length].val = *val;
+  entries[length].val.initNullAfterMalloc();
+  entries[length].val = std::move(val);
   ++length;
 }
 
@@ -208,7 +206,6 @@
   } else {
     int i; 
     bool found = false;
-    DictEntry tmp;
     if(length == 0) {
       return;
     }
@@ -226,25 +223,26 @@
     gfree(entries[i].key);
     entries[i].val.free();
     length -= 1;
-    tmp = entries[length];
-    if (i!=length) //don't copy the last entry if it is deleted 
-      entries[i] = tmp;
+    if (i!=length) {
+      //don't copy the last entry if it is deleted
+      entries[i].key = entries[length].key;
+      entries[i].val = std::move(entries[length].val);
+    }
   }
 }
 
-void Dict::set(const char *key, Object *val) {
+void Dict::set(const char *key, Object &&val) {
   DictEntry *e;
-  if (val->isNull()) {
+  if (val.isNull()) {
     remove(key);
     return;
   }
   e = find (key);
   if (e) {
     dictLocker();
-    e->val.free();
-    e->val = *val;
+    e->val = std::move(val);
   } else {
-    add (copyString(key), val);
+    add (copyString(key), std::move(val));
   }
 }
 
@@ -255,27 +253,25 @@
   return (e = find("Type")) && e->val.isName(type);
 }
 
-Object *Dict::lookup(const char *key, Object *obj, int recursion) {
+Object Dict::lookup(const char *key, int recursion) {
   DictEntry *e;
 
-  return (e = find(key)) ? e->val.fetch(xref, obj, recursion) : obj->initNull();
+  return (e = find(key)) ? e->val.fetch(xref, recursion) : Object(objNull);
 }
 
-Object *Dict::lookupNF(const char *key, Object *obj) {
+Object Dict::lookupNF(const char *key) {
   DictEntry *e;
 
-  return (e = find(key)) ? e->val.copy(obj) : obj->initNull();
+  return (e = find(key)) ? e->val.copy() : Object(objNull);
 }
 
 GBool Dict::lookupInt(const char *key, const char *alt_key, int *value)
 {
-  Object obj1;
   GBool success = gFalse;
-  
-  lookup ((char *) key, &obj1);
+  Object obj1 = lookup ((char *) key);
   if (obj1.isNull () && alt_key != NULL) {
     obj1.free ();
-    lookup ((char *) alt_key, &obj1);
+    obj1 = lookup ((char *) alt_key);
   }
   if (obj1.isInt ()) {
     *value = obj1.getInt ();
@@ -291,10 +287,10 @@
   return entries[i].key;
 }
 
-Object *Dict::getVal(int i, Object *obj) {
-  return entries[i].val.fetch(xref, obj);
+Object Dict::getVal(int i) {
+  return entries[i].val.fetch(xref);
 }
 
-Object *Dict::getValNF(int i, Object *obj) {
-  return entries[i].val.copy(obj);
+Object Dict::getValNF(int i) {
+  return entries[i].val.copy();
 }
diff --git a/poppler/Dict.h b/poppler/Dict.h
index fba99ed..b775a57 100644
--- a/poppler/Dict.h
+++ b/poppler/Dict.h
@@ -16,7 +16,7 @@
 // Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
 // Copyright (C) 2006 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
 // Copyright (C) 2007-2008 Julien Rebetez <julienr@svn.gnome.org>
-// Copyright (C) 2010 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2010, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2010 Paweł Wiejacha <pawel.wiejacha@gmail.com>
 // Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
 //
@@ -56,18 +56,16 @@
   // Destructor.
   ~Dict();
 
-  // Reference counting.
-  int incRef();
-  int decRef();
-
   // Get number of entries.
   int getLength() { return length; }
 
   // Add an entry.  NB: does not copy key.
-  void add(char *key, Object *val);
+  // val becomes a dead object after the call
+  void add(char *key, Object &&val);
 
   // Update the value of an existing entry, otherwise create it
-  void set(const char *key, Object *val);
+  // val becomes a dead object after the call
+  void set(const char *key, Object &&val);
   // Remove an entry. This invalidate indexes
   void remove(const char *key);
 
@@ -76,14 +74,14 @@
 
   // Look up an entry and return the value.  Returns a null object
   // if <key> is not in the dictionary.
-  Object *lookup(const char *key, Object *obj, int recursion = 0);
-  Object *lookupNF(const char *key, Object *obj);
+  Object lookup(const char *key, int recursion = 0);
+  Object lookupNF(const char *key);
   GBool lookupInt(const char *key, const char *alt_key, int *value);
 
   // Iterative accessors.
   char *getKey(int i);
-  Object *getVal(int i, Object *obj);
-  Object *getValNF(int i, Object *obj);
+  Object getVal(int i);
+  Object getValNF(int i);
 
   // Set the xref pointer.  This is only used in one special case: the
   // trailer dictionary, which is read before the xref table is
@@ -95,6 +93,11 @@
   GBool hasKey(const char *key);
 
 private:
+  friend class Object; // for incRef/decRef
+
+  // Reference counting.
+  int incRef();
+  int decRef();
 
   GBool sorted;
   XRef *xref;			// the xref table for this PDF file
diff --git a/poppler/FileSpec.cc b/poppler/FileSpec.cc
index bac1eae..5ebef97 100644
--- a/poppler/FileSpec.cc
+++ b/poppler/FileSpec.cc
@@ -7,7 +7,7 @@
 //
 // Copyright (C) 2008-2009 Carlos Garcia Campos <carlosgc@gnome.org>
 // Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
-// Copyright (C) 2012 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2012, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2012 Hib Eris <hib@hiberis.nl>
 //
 // To see a description of the changes please see the Changelog file that
@@ -35,40 +35,37 @@
   m_checksum = NULL;
   m_mimetype = NULL;
 
-  efStream->copy(&m_objStr);
+  m_objStr = efStream->copy();
 
   if (efStream->isStream()) {
     // dataDict corresponds to Table 3.41 in the PDF1.6 spec.
     Dict *dataDict = efStream->streamGetDict();
 
     // subtype is normally the mimetype
-    Object subtypeName;
-    if (dataDict->lookup("Subtype", &subtypeName)->isName()) {
+    Object subtypeName = dataDict->lookup("Subtype");
+    if (subtypeName.isName()) {
       m_mimetype = new GooString(subtypeName.getName());
     }
-    subtypeName.free();
 
     // paramDict corresponds to Table 3.42 in the PDF1.6 spec
-    Object paramDict;
-    if (dataDict->lookup("Params", &paramDict)->isDict()) {
-      Object paramObj;
-      if (paramDict.dictLookup("ModDate", &paramObj)->isString())
+    Object paramDict = dataDict->lookup("Params");
+    if (paramDict.isDict()) {
+      Object paramObj = paramDict.dictLookup("ModDate");
+      if (paramObj.isString())
         m_modDate = new GooString(paramObj.getString());
-      paramObj.free();
 
-      if (paramDict.dictLookup("CreationDate", &paramObj)->isString())
+      paramObj = paramDict.dictLookup("CreationDate");
+      if (paramObj.isString())
         m_createDate = new GooString(paramObj.getString());
-      paramObj.free();
 
-      if (paramDict.dictLookup("Size", &paramObj)->isInt())
+      paramObj = paramDict.dictLookup("Size");
+      if (paramObj.isInt())
         m_size = paramObj.getInt();
-      paramObj.free();
 
-      if (paramDict.dictLookup("CheckSum", &paramObj)->isString())
+      paramObj = paramDict.dictLookup("CheckSum");
+      if (paramObj.isString())
         m_checksum = new GooString(paramObj.getString());
-      paramObj.free();
     }
-    paramDict.free();
   }
 }
 
@@ -78,7 +75,6 @@
   delete m_modDate;
   delete m_checksum;
   delete m_mimetype;
-  m_objStr.free();
 }
 
 GBool EmbFile::save(const char *path) {
@@ -110,41 +106,37 @@
   platformFileName = NULL;
   embFile = NULL;
   desc = NULL;
-  fileSpecA->copy(&fileSpec);
+  fileSpec = fileSpecA->copy();
 
-  Object obj1;
-  if (!getFileSpecName(fileSpecA, &obj1)) {
+  Object obj1 = getFileSpecName(fileSpecA);
+  if (!obj1.isString()) {
     ok = gFalse;
-    obj1.free();
     error(errSyntaxError, -1, "Invalid FileSpec");
     return;
   }
 
   fileName = obj1.getString()->copy();
-  obj1.free();
 
   if (fileSpec.isDict()) {
-    if (fileSpec.dictLookup("EF", &obj1)->isDict()) {
-      if (!obj1.dictLookupNF("F", &fileStream)->isRef()) {
+    obj1 = fileSpec.dictLookup("EF");
+    if (obj1.isDict()) {
+      fileStream = obj1.dictLookupNF("F");
+      if (!fileStream.isRef()) {
         ok = gFalse;
-        fileStream.free();
+        fileStream.setToNull();
         error(errSyntaxError, -1, "Invalid FileSpec: Embedded file stream is not an indirect reference");
-        obj1.free();
         return;
       }
     }
-    obj1.free();
   }
 
-  if (fileSpec.dictLookup("Desc", &obj1)->isString())
+  obj1 = fileSpec.dictLookup("Desc");
+  if (obj1.isString())
     desc = obj1.getString()->copy();
-  obj1.free();
 }
 
 FileSpec::~FileSpec()
 {
-  fileSpec.free();
-  fileStream.free();
   delete fileName;
   delete platformFileName;
   delete embFile;
@@ -161,8 +153,8 @@
 
   Object obj1;
   XRef *xref = fileSpec.getDict()->getXRef();
-  embFile = new EmbFile(fileStream.fetch(xref, &obj1));
-  obj1.free();
+  obj1 = fileStream.fetch(xref);
+  embFile = new EmbFile(&obj1);
 
   return embFile;
 }
@@ -172,84 +164,77 @@
   if (platformFileName)
     return platformFileName;
 
-  Object obj1;
-  if (getFileSpecNameForPlatform(&fileSpec, &obj1))
+  Object obj1 = getFileSpecNameForPlatform(&fileSpec);
+  if (obj1.isString())
     platformFileName = obj1.getString()->copy();
-  obj1.free();
 
   return platformFileName;
 }
 
-GBool getFileSpecName (Object *fileSpec, Object *fileName)
+Object getFileSpecName (Object *fileSpec)
 {
   if (fileSpec->isString()) {
-    fileSpec->copy(fileName);
-    return gTrue;
+    return fileSpec->copy();
   }
   
   if (fileSpec->isDict()) {
-    fileSpec->dictLookup("UF", fileName);
-    if (fileName->isString()) {
-      return gTrue;
+    Object fileName = fileSpec->dictLookup("UF");
+    if (fileName.isString()) {
+      return fileName;
     }
-    fileName->free();
-    fileSpec->dictLookup("F", fileName);
-    if (fileName->isString()) {
-      return gTrue;
+    fileName = fileSpec->dictLookup("F");
+    if (fileName.isString()) {
+      return fileName;
     }
-    fileName->free();
-    fileSpec->dictLookup("DOS", fileName);
-    if (fileName->isString()) {
-      return gTrue;
+    fileName = fileSpec->dictLookup("DOS");
+    if (fileName.isString()) {
+      return fileName;
     }
-    fileName->free();
-    fileSpec->dictLookup("Mac", fileName);
-    if (fileName->isString()) {
-      return gTrue;
+    fileName = fileSpec->dictLookup("Mac");
+    if (fileName.isString()) {
+      return fileName;
     }
-    fileName->free();
-    fileSpec->dictLookup("Unix", fileName);
-    if (fileName->isString()) {
-      return gTrue;
+    fileName = fileSpec->dictLookup("Unix");
+    if (fileName.isString()) {
+      return fileName;
     }
-    fileName->free();
   }
-  return gFalse;
+  return Object();
 }
 
-GBool getFileSpecNameForPlatform (Object *fileSpec, Object *fileName)
+Object getFileSpecNameForPlatform (Object *fileSpec)
 {
   if (fileSpec->isString()) {
-    fileSpec->copy(fileName);
-    return gTrue;
+    return fileSpec->copy();
   }
 
+  Object fileName;
   if (fileSpec->isDict()) {
-    if (!fileSpec->dictLookup("UF", fileName)->isString ()) {
-      fileName->free();
-      if (!fileSpec->dictLookup("F", fileName)->isString ()) {
-        fileName->free();
+    fileName = fileSpec->dictLookup("UF");
+    if (!fileName.isString ()) {
+      fileName = fileSpec->dictLookup("F");
+      if (!fileName.isString ()) {
 #ifdef _WIN32
 	const char *platform = "DOS";
 #else
 	const char *platform = "Unix";
 #endif
-	if (!fileSpec->dictLookup(platform, fileName)->isString ()) {
-	  fileName->free();
+        fileName = fileSpec->dictLookup(platform);
+	if (!fileName.isString ()) {
 	  error(errSyntaxError, -1, "Illegal file spec");
-	  return gFalse;
+	  return Object();
 	}
       }
     }
   } else {
     error(errSyntaxError, -1, "Illegal file spec");
-    return gFalse;
+    return Object();
   }
 
   // system-dependent path manipulation
 #ifdef _WIN32
   int i, j;
-  GooString *name = fileName->getString();
+  GooString *name = fileName.getString();
   // "//...."             --> "\...."
   // "/x/...."            --> "x:\...."
   // "/server/share/...." --> "\\server\share\...."
@@ -291,5 +276,5 @@
   }
 #endif /* _WIN32 */
 
-  return gTrue;
+  return fileName;
 }
diff --git a/poppler/FileSpec.h b/poppler/FileSpec.h
index 9f2f6fc..6133117 100644
--- a/poppler/FileSpec.h
+++ b/poppler/FileSpec.h
@@ -6,6 +6,7 @@
 // under GPL version 2 or later
 //
 // Copyright (C) 2008 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2017 Albert Astals Cid <aacid@kde.org>
 //
 // 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
@@ -31,6 +32,7 @@
   GooString *createDate() { return m_createDate; }
   GooString *checksum() { return m_checksum; }
   GooString *mimeType() { return m_mimetype; }
+  Object *streamObject() { return &m_objStr; }
   Stream *stream() { return isOk() ? m_objStr.getStream() : NULL; }
   GBool isOk() { return m_objStr.isStream(); }
   GBool save(const char *path);
@@ -70,7 +72,7 @@
   GooString *desc;             // Desc
 };
 
-GBool getFileSpecName (Object *fileSpec, Object *fileName);
-GBool getFileSpecNameForPlatform (Object *fileSpec, Object *fileName);
+Object getFileSpecName (Object *fileSpec);
+Object getFileSpecNameForPlatform (Object *fileSpec);
 
 #endif /* FILE_SPEC_H */
diff --git a/poppler/FontInfo.cc b/poppler/FontInfo.cc
index 8fc89e9..3730f52 100644
--- a/poppler/FontInfo.cc
+++ b/poppler/FontInfo.cc
@@ -3,7 +3,7 @@
 // FontInfo.cc
 //
 // Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
-// Copyright (C) 2005-2008, 2010 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2005-2008, 2010, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2005 Brad Hards <bradh@frogmouth.net>
 // Copyright (C) 2006 Kouhei Sutou <kou@cozmixng.org>
 // Copyright (C) 2009 Pino Toscano <pino@kde.org>
@@ -54,7 +54,6 @@
   Page *page;
   Dict *resDict;
   Annots *annots;
-  Object obj1;
   int lastPage;
 
   if (currentPage > doc->getNumPages()) {
@@ -79,10 +78,10 @@
     }
     annots = page->getAnnots();
     for (int i = 0; i < annots->getNumAnnots(); ++i) {
-      if (annots->getAnnot(i)->getAppearanceResDict(&obj1)->isDict()) {
+      Object obj1 = annots->getAnnot(i)->getAppearanceResDict();
+      if (obj1.isDict()) {
         scanFonts(xrefA, obj1.getDict(), result);
       }
-      obj1.free();
     }
   }
 
@@ -93,27 +92,24 @@
 }
 
 void FontInfoScanner::scanFonts(XRef *xrefA, Dict *resDict, GooList *fontsList) {
-  Object obj1, obj2, objDict, resObj;
   Ref r;
   GfxFontDict *gfxFontDict;
   GfxFont *font;
-  int i;
 
   // scan the fonts in this resource dictionary
   gfxFontDict = NULL;
-  resDict->lookupNF("Font", &obj1);
+  Object obj1 = resDict->lookupNF("Font");
   if (obj1.isRef()) {
-    obj1.fetch(xrefA, &obj2);
+    Object obj2 = obj1.fetch(xrefA);
     if (obj2.isDict()) {
       r = obj1.getRef();
       gfxFontDict = new GfxFontDict(xrefA, &r, obj2.getDict());
     }
-    obj2.free();
   } else if (obj1.isDict()) {
     gfxFontDict = new GfxFontDict(xrefA, NULL, obj1.getDict());
   }
   if (gfxFontDict) {
-    for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
+    for (int i = 0; i < gfxFontDict->getNumFonts(); ++i) {
       if ((font = gfxFontDict->getFont(i))) {
         Ref fontRef = *font->getID();
 
@@ -126,48 +122,39 @@
     }
     delete gfxFontDict;
   }
-  obj1.free();
 
   // recursively scan any resource dictionaries in objects in this
   // resource dictionary
   const char *resTypes[] = { "XObject", "Pattern" };
   for (Guint resType = 0; resType < sizeof(resTypes) / sizeof(resTypes[0]); ++resType) {
-    resDict->lookup(resTypes[resType], &objDict);
+    Object objDict = resDict->lookup(resTypes[resType]);
     if (objDict.isDict()) {
-      for (i = 0; i < objDict.dictGetLength(); ++i) {
-        objDict.dictGetValNF(i, &obj1);
+      for (int i = 0; i < objDict.dictGetLength(); ++i) {
+        obj1 = objDict.dictGetValNF(i);
         if (obj1.isRef()) {
           // check for an already-seen object
           const Ref r = obj1.getRef();
           if (visitedObjects.find(r.num) != visitedObjects.end()) {
-            obj1.free();
             continue;
           }
 
           visitedObjects.insert(r.num);
         }
 
-        obj1.fetch(xrefA, &obj2);
-
+        Object obj2 = obj1.fetch(xrefA);
         if (obj2.isStream()) {
-          obj2.streamGetDict()->lookup("Resources", &resObj);
+          Object resObj = obj2.streamGetDict()->lookup("Resources");
           if (resObj.isDict() && resObj.getDict() != resDict) {
             scanFonts(xrefA, resObj.getDict(), fontsList);
           }
-          resObj.free();
         }
-        obj1.free();
-        obj2.free();
       }
     }
-    objDict.free();
   }
 }
 
 FontInfo::FontInfo(GfxFont *font, XRef *xref) {
   GooString *origName;
-  Object fontObj, toUnicodeObj;
-  int i;
 
   fontRef = *font->getID();
 
@@ -204,16 +191,16 @@
 
   // look for a ToUnicode map
   hasToUnicode = gFalse;
-  if (xref->fetch(fontRef.num, fontRef.gen, &fontObj)->isDict()) {
-    hasToUnicode = fontObj.dictLookup("ToUnicode", &toUnicodeObj)->isStream();
-    toUnicodeObj.free();
+  Object fontObj = xref->fetch(fontRef.num, fontRef.gen);
+  if (fontObj.isDict()) {
+    hasToUnicode = fontObj.dictLookup("ToUnicode").isStream();
   }
-  fontObj.free();
 
   // check for a font subset name: capital letters followed by a '+'
   // sign
   subset = gFalse;
   if (name) {
+    int i;
     for (i = 0; i < name->getLength(); ++i) {
       if (name->getChar(i) < 'A' || name->getChar(i) > 'Z') {
 	break;
diff --git a/poppler/Form.cc b/poppler/Form.cc
index 4627a43..aaf9684 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -86,7 +86,7 @@
   childNum = num;
   doc = docA;
   xref = doc->getXRef();
-  aobj->copy(&obj);
+  obj = aobj->copy();
   type = formUndef;
   field = fieldA;
   widget = NULL;
@@ -96,7 +96,6 @@
 {
   if (widget)
     widget->decRefCnt();
-  obj.free ();
 }
 
 #ifdef DEBUG_FORMS
@@ -109,10 +108,8 @@
   if (widget)
     return;
 
-  Object obj1;
-  obj1.initRef(ref.num, ref.gen);
-  widget = new AnnotWidget(doc, obj.getDict(), &obj1, field);
-  obj1.free();
+  Object obj1(ref.num, ref.gen);
+  widget = new AnnotWidget(doc, &obj, &obj1, field);
 }
 
 GBool FormWidget::inRect(double x, double y) const {
@@ -179,13 +176,13 @@
   type = formButton;
   onStr = NULL;
 
-  Object obj1, obj2;
-
   // Find the name of the ON state in the AP dictionnary
   // The reference say the Off state, if it existe, _must_ be stored in the AP dict under the name /Off
   // The "on" state may be stored under any other name
-  if (obj.dictLookup("AP", &obj1)->isDict()) {
-    if (obj1.dictLookup("N", &obj2)->isDict()) {
+  Object obj1 = obj.dictLookup("AP");
+  if (obj1.isDict()) {
+    Object obj2 = obj1.dictLookup("N");
+    if (obj2.isDict()) {
       for (int i = 0; i < obj2.dictGetLength(); i++) {
         char *key = obj2.dictGetKey(i);
         if (strcmp (key, "Off") != 0) {
@@ -194,9 +191,7 @@
         }
       }
     }
-    obj2.free();
   }
-  obj1.free();
 }
 
 char *FormWidgetButton::getOnStr() {
@@ -463,7 +458,7 @@
 {
   doc = docA;
   xref = doc->getXRef();
-  aobj->copy(&obj);
+  obj = aobj->copy();
   Dict* dict = obj.getDict();
   ref.num = ref.gen = 0;
   type = ty;
@@ -480,76 +475,65 @@
 
   ref = aref;
 
-  Object obj1;
   //childs
-  if (dict->lookup("Kids", &obj1)->isArray()) {
+  Object obj1 = dict->lookup("Kids");
+  if (obj1.isArray()) {
     // Load children
     for (int i = 0 ; i < obj1.arrayGetLength(); i++) {
-      Object childRef, childObj;
-
-      if (!obj1.arrayGetNF(i, &childRef)->isRef()) {
+      Object childRef = obj1.arrayGetNF(i);
+      if (!childRef.isRef()) {
         error (errSyntaxError, -1, "Invalid form field renference");
-        childRef.free();
         continue;
       }
-      if (!obj1.arrayGet(i, &childObj)->isDict()) {
+      Object childObj = obj1.arrayGet(i);
+      if (!childObj.isDict()) {
         error (errSyntaxError, -1, "Form field child is not a dictionary");
-        childObj.free();
-        childRef.free();
         continue;
       }
 
       const Ref ref = childRef.getRef();
       if (usedParents->find(ref.num) == usedParents->end()) {
-        Object obj2, obj3;
         // Field child: it could be a form field or a widget or composed dict
-        if (childObj.dictLookupNF("Parent", &obj2)->isRef() || childObj.dictLookup("Parent", &obj3)->isDict()) {
+        Object obj2 = childObj.dictLookupNF("Parent");
+	Object obj3 = childObj.dictLookup("Parent");
+        if (obj2.isRef() || obj3.isDict()) {
           // Child is a form field or composed dict
           // We create the field, if it's composed
           // it will create the widget as a child
           std::set<int> usedParentsAux = *usedParents;
           usedParentsAux.insert(ref.num);
-          obj2.free();
-          obj3.free();
 
           if (terminal) {
             error(errSyntaxWarning, -1, "Field can't have both Widget AND Field as kids\n");
-            childObj.free();
-            childRef.free();
             continue;
           }
 
           numChildren++;
           children = (FormField**)greallocn(children, numChildren, sizeof(FormField*));
           children[numChildren - 1] = Form::createFieldFromDict(&childObj, doc, ref, this, &usedParentsAux);
-        } else if (childObj.dictLookup("Subtype", &obj2)->isName("Widget")) {
-          // Child is a widget annotation
-          if (!terminal && numChildren > 0) {
-            error(errSyntaxWarning, -1, "Field can't have both Widget AND Field as kids\n");
-            obj2.free();
-            obj3.free();
-            childObj.free();
-            childRef.free();
-            continue;
-          }
-          _createWidget(&childObj, ref);
-        }
-        obj2.free();
-        obj3.free();
+        } else {
+	  obj2 = childObj.dictLookup("Subtype");
+	  if (obj2.isName("Widget")) {
+	    // Child is a widget annotation
+	    if (!terminal && numChildren > 0) {
+	      error(errSyntaxWarning, -1, "Field can't have both Widget AND Field as kids\n");
+	      continue;
+	    }
+	    _createWidget(&childObj, ref);
+	  }
+	}
       }
-      childObj.free();
-      childRef.free();
     }
   } else {
     // No children, if it's a composed dict, create the child widget
-    obj1.free();
-    if (dict->lookup("Subtype", &obj1)->isName("Widget"))
+    obj1 = dict->lookup("Subtype");
+    if (obj1.isName("Widget"))
       _createWidget(&obj, ref);
   }
-  obj1.free();
 
   //flags
-  if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
+  obj1 = Form::fieldLookup(dict, "Ff");
+  if (obj1.isInt()) {
     int flags = obj1.getInt();
     if (flags & 0x1) { // 1 -> ReadOnly
       readOnly = true;
@@ -561,39 +545,38 @@
       //TODO
     }
   }
-  obj1.free();
 
   // Variable Text
-  if (Form::fieldLookup(dict, "DA", &obj1)->isString())
+  obj1 = Form::fieldLookup(dict, "DA");
+  if (obj1.isString())
     defaultAppearance = obj1.getString()->copy();
-  obj1.free();
 
-  if (Form::fieldLookup(dict, "Q", &obj1)->isInt()) {
+  obj1 = Form::fieldLookup(dict, "Q");
+  if (obj1.isInt()) {
     quadding = static_cast<VariableTextQuadding>(obj1.getInt());
     hasQuadding = gTrue;
   }
-  obj1.free();
 
-  if (dict->lookup("T", &obj1)->isString()) {
+  obj1 = dict->lookup("T");
+  if (obj1.isString()) {
     partialName = obj1.getString()->copy();
   } else {
     partialName = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("TU", &obj1)->isString()) {
+  obj1 = dict->lookup("TU");
+  if (obj1.isString()) {
     alternateUiName = obj1.getString()->copy();
   } else {
     alternateUiName = NULL;
   }
-  obj1.free();
 
-  if(dict->lookup("TM", &obj1)->isString()) {
+  obj1 = dict->lookup("TM");
+  if(obj1.isString()) {
     mappingName = obj1.getString()->copy();
   } else {
     mappingName = NULL;
   }
-  obj1.free();
 }
 
 void FormField::setPartialName(const GooString &name)
@@ -601,9 +584,7 @@
   delete partialName;
   partialName = name.copy();
 
-  Object obj1;
-  obj1.initString(name.copy());
-  obj.getDict()->set("T", &obj1);
+  obj.getDict()->set("T", Object(name.copy()));
   xref->setModifiedObject(&obj, ref);
 }
 
@@ -620,7 +601,6 @@
       delete widgets[i];
     gfree (widgets);
   }
-  obj.free();
 
   delete defaultAppearance;
   delete partialName;
@@ -690,7 +670,6 @@
   default:
     error(errSyntaxWarning, -1, "SubType on non-terminal field, invalid document?");
     numChildren--;
-    terminal = false;
   }
 }
 
@@ -712,7 +691,7 @@
 }
 
 GooString* FormField::getFullyQualifiedName() {
-  Object obj1, obj2;
+  Object obj1;
   Object parent;
   GooString *parent_name;
   GooString *full_name;
@@ -723,9 +702,10 @@
 
   full_name = new GooString();
 
-  obj.copy(&obj1);
-  while (obj1.dictLookup("Parent", &parent)->isDict()) {
-    if (parent.dictLookup("T", &obj2)->isString()) {
+  obj1 = obj.copy();
+  while (parent = obj1.dictLookup("Parent"), parent.isDict()) {
+    Object obj2 = parent.dictLookup("T");
+    if (obj2.isString()) {
       parent_name = obj2.getString();
 
       if (unicode_encoded) {
@@ -748,14 +728,9 @@
           full_name->insert(0, parent_name);
         }
       }
-      obj2.free();
     }
-    obj1.free();
-    parent.copy(&obj1);
-    parent.free();
+    obj1 = parent.copy();
   }
-  obj1.free();
-  parent.free();
 
   if (partialName) {
     if (unicode_encoded) {
@@ -822,11 +797,11 @@
   noAllOff = false;
   siblings = NULL;
   numSiblings = 0;
-  appearanceState.initNull();
+  appearanceState.setToNull();
 
-  Object obj1;
-  btype = formButtonCheck; 
-  if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
+  btype = formButtonCheck;
+  Object obj1 = Form::fieldLookup(dict, "Ff");
+  if (obj1.isInt()) {
     int flags = obj1.getInt();
     
     if (flags & 0x10000) { // 17 -> push button
@@ -845,7 +820,7 @@
   if (btype != formButtonPush) {
     // Even though V is inheritable we are interested in the value of this
     // field, if not present it's probably because it's a button in a set.
-    dict->lookup("V", &appearanceState);
+    appearanceState = dict->lookup("V");
   }
 }
 
@@ -969,19 +944,13 @@
 }
 
 void FormFieldButton::updateState(char *state) {
-  Object obj1;
-
-  appearanceState.free();
-  appearanceState.initName(state);
-
-  appearanceState.copy(&obj1);
-  obj.getDict()->set("V", &obj1);
+  appearanceState = Object(objName, state);
+  obj.getDict()->set("V", appearanceState.copy());
   xref->setModifiedObject(&obj, ref);
 }
 
 FormFieldButton::~FormFieldButton()
 {
-  appearanceState.free();
   if (siblings)
     gfree(siblings);
 }
@@ -998,7 +967,8 @@
   multiline = password = fileSelect = doNotSpellCheck = doNotScroll = comb = richText = false;
   maxLen = 0;
 
-  if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
+  obj1 = Form::fieldLookup(dict, "Ff");
+  if (obj1.isInt()) {
     int flags = obj1.getInt();
     if (flags & 0x1000) // 13 -> Multiline
       multiline = true;
@@ -1015,14 +985,14 @@
     if (flags & 0x2000000)// 26 -> RichText
       richText = true;
   }
-  obj1.free();
 
-  if (Form::fieldLookup(dict, "MaxLen", &obj1)->isInt()) {
+  obj1 = Form::fieldLookup(dict, "MaxLen");
+  if (obj1.isInt()) {
     maxLen = obj1.getInt();
   }
-  obj1.free();
 
-  if (Form::fieldLookup(dict, "V", &obj1)->isString()) {
+  obj1 = Form::fieldLookup(dict, "V");
+  if (obj1.isString()) {
     if (obj1.getString()->hasUnicodeMarker()) {
       if (obj1.getString()->getLength() > 2)
         content = obj1.getString()->copy();
@@ -1034,7 +1004,6 @@
       delete [] tmp_str;
     }
   }
-  obj1.free();
 }
 
 #ifdef DEBUG_FORMS
@@ -1066,9 +1035,7 @@
     }
   }
 
-  Object obj1;
-  obj1.initString(content ? content->copy() : new GooString(""));
-  obj.getDict()->set("V", &obj1);
+  obj.getDict()->set("V", Object(content ? content->copy() : new GooString("")));
   xref->setModifiedObject(&obj, ref);
   updateChildrenAppearance();
 }
@@ -1095,7 +1062,8 @@
 
   combo = edit = multiselect = doNotSpellCheck = doCommitOnSelChange = false;
 
-  if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
+  obj1 = Form::fieldLookup(dict, "Ff");
+  if (obj1.isInt()) {
     int flags = obj1.getInt();
     if (flags & 0x20000) // 18 -> Combo
       combo = true; 
@@ -1108,67 +1076,62 @@
     if (flags & 0x4000000) // 27 -> CommitOnSelChange
       doCommitOnSelChange = true;
   }
-  obj1.free();
 
-  if (dict->lookup("TI", &obj1)->isInt())
+  obj1 = dict->lookup("TI");
+  if (obj1.isInt())
     topIdx = obj1.getInt();
-  obj1.free();
 
-  if (dict->lookup("Opt", &obj1)->isArray()) {
-    Object obj2;
-
+  obj1 = dict->lookup("Opt");
+  if (obj1.isArray()) {
     numChoices = obj1.arrayGetLength();
     choices = new ChoiceOpt[numChoices];
     memset(choices, 0, sizeof(ChoiceOpt) * numChoices);
 
     for (int i = 0; i < numChoices; i++) {
-      if (obj1.arrayGet(i, &obj2)->isString()) {
+      Object obj2 = obj1.arrayGet(i);
+      if (obj2.isString()) {
         choices[i].optionName = obj2.getString()->copy();
       } else if (obj2.isArray()) { // [Export_value, Displayed_text]
-        Object obj3;
-
         if (obj2.arrayGetLength() < 2) {
           error(errSyntaxError, -1, "FormWidgetChoice:: invalid Opt entry -- array's length < 2\n");
           continue;
         }
-        if (obj2.arrayGet(0, &obj3)->isString())
+        Object obj3 = obj2.arrayGet(0);
+        if (obj3.isString())
           choices[i].exportVal = obj3.getString()->copy();
         else
           error(errSyntaxError, -1, "FormWidgetChoice:: invalid Opt entry -- exported value not a string\n");
-        obj3.free();
 
-        if (obj2.arrayGet(1, &obj3)->isString())
+        obj3 = obj2.arrayGet(1);
+        if (obj3.isString())
           choices[i].optionName = obj3.getString()->copy();
         else
           error(errSyntaxError, -1, "FormWidgetChoice:: invalid Opt entry -- choice name not a string\n");
-        obj3.free();
       } else {
         error(errSyntaxError, -1, "FormWidgetChoice:: invalid {0:d} Opt entry\n", i);
       }
-      obj2.free();
     }
   } else {
     //empty choice
   }
-  obj1.free();
 
   // Find selected items
   // Note: PDF specs say that /V has precedence over /I, but acroread seems to
   // do the opposite. We do the same.
-  if (Form::fieldLookup(dict, "I", &obj1)->isArray()) {
+  obj1 = Form::fieldLookup(dict, "I");
+  if (obj1.isArray()) {
     for (int i = 0; i < obj1.arrayGetLength(); i++) {
-      Object obj2;
-      if (obj1.arrayGet(i, &obj2)->isInt() && obj2.getInt() >= 0 && obj2.getInt() < numChoices) {
+      Object obj2 = obj1.arrayGet(i);
+      if (obj2.isInt() && obj2.getInt() >= 0 && obj2.getInt() < numChoices) {
         choices[obj2.getInt()].selected = true;
       }
-      obj2.free();
     }
   } else {
-    obj1.free();
     // Note: According to PDF specs, /V should *never* contain the exportVal.
     // However, if /Opt is an array of (exportVal,optionName) pairs, acroread
     // seems to expect the exportVal instead of the optionName and so we do too.
-    if (Form::fieldLookup(dict, "V", &obj1)->isString()) {
+    obj1 = Form::fieldLookup(dict, "V");
+    if (obj1.isString()) {
       GBool optionFound = gFalse;
 
       for (int i = 0; i < numChoices; i++) {
@@ -1195,8 +1158,7 @@
     } else if (obj1.isArray()) {
       for (int i = 0; i < numChoices; i++) {
         for (int j = 0; j < obj1.arrayGetLength(); j++) {
-          Object obj2;
-          obj1.arrayGet(j, &obj2);
+          Object obj2 = obj1.arrayGet(j);
           GBool matches = gFalse;
 
           if (choices[i].exportVal) {
@@ -1209,8 +1171,6 @@
             }
           }
 
-          obj2.free();
-
           if (matches) {
             choices[i].selected = true;
             break; // We've determined that this option is selected. No need to keep on scanning
@@ -1219,7 +1179,6 @@
       }
     }
   }
-  obj1.free();
 }
 
 FormFieldChoice::~FormFieldChoice()
@@ -1241,35 +1200,35 @@
 #endif
 
 void FormFieldChoice::updateSelection() {
-  Object objV, objI, obj1;
-  objI.initNull();
+  Object objV, obj1;
+  Object objI(objNull);
 
   if (edit && editedChoice) {
     // This is an editable combo-box with user-entered text
-    objV.initString(editedChoice->copy());
+    objV = Object(editedChoice->copy());
   } else {
     const int numSelected = getNumSelected();
 
     // Create /I array only if multiple selection is allowed (as per PDF spec)
     if (multiselect) {
-      objI.initArray(xref);
+      objI = Object(new Array(xref));
     }
 
     if (numSelected == 0) {
       // No options are selected
-      objV.initString(new GooString(""));
+      objV = Object(new GooString(""));
     } else if (numSelected == 1) {
       // Only one option is selected
       for (int i = 0; i < numChoices; i++) {
         if (choices[i].selected) {
           if (multiselect) {
-            objI.arrayAdd(obj1.initInt(i));
+            objI.arrayAdd(Object(i));
           }
 
           if (choices[i].exportVal) {
-            objV.initString(choices[i].exportVal->copy());
+            objV = Object(choices[i].exportVal->copy());
           } else if (choices[i].optionName) {
-            objV.initString(choices[i].optionName->copy());
+            objV = Object(choices[i].optionName->copy());
           }
 
           break; // We've just written the selected option. No need to keep on scanning
@@ -1277,25 +1236,25 @@
       }
     } else {
       // More than one option is selected
-      objV.initArray(xref);
+      objV = Object(new Array(xref));
       for (int i = 0; i < numChoices; i++) {
         if (choices[i].selected) {
           if (multiselect) {
-            objI.arrayAdd(obj1.initInt(i));
+            objI.arrayAdd(Object(i));
           }
 
           if (choices[i].exportVal) {
-            objV.arrayAdd(obj1.initString(choices[i].exportVal->copy()));
+            objV.arrayAdd(Object(choices[i].exportVal->copy()));
           } else if (choices[i].optionName) {
-            objV.arrayAdd(obj1.initString(choices[i].optionName->copy()));
+            objV.arrayAdd(Object(choices[i].optionName->copy()));
           }
         }
       }
     }
   }
 
-  obj.getDict()->set("V", &objV);
-  obj.getDict()->set("I", &objI);
+  obj.getDict()->set("V", std::move(objV));
+  obj.getDict()->set("I", std::move(objI));
   xref->setModifiedObject(&obj, ref);
   updateChildrenAppearance();
 }
@@ -1396,7 +1355,6 @@
 
 FormFieldSignature::~FormFieldSignature()
 {
-  byte_range.free();
   delete signature_info;
   delete signature;
 }
@@ -1406,39 +1364,31 @@
   if (!obj.isDict())
     return;
 
-  Object sig_dict, contents_obj, time_of_signing, subfilterName;
-
   // retrieve PKCS#7
-  obj.dictLookup("V", &sig_dict);
+  Object sig_dict = obj.dictLookup("V");
   if (!sig_dict.isDict()) {
-    sig_dict.free();
     return;
   }
 
-  sig_dict.dictLookup("Contents", &contents_obj);
+  Object contents_obj = sig_dict.dictLookup("Contents");
   if (contents_obj.isString()) {
     signature = contents_obj.getString()->copy();
   }
-  contents_obj.free();
 
-  sig_dict.dictLookup("ByteRange", &byte_range);
+  Object byte_range = sig_dict.dictLookup("ByteRange");
 
   // retrieve SigningTime
-  sig_dict.dictLookup("M", &time_of_signing);
+  Object time_of_signing = sig_dict.dictLookup("M");
   if (time_of_signing.isString()) {
     GooString *time_str = time_of_signing.getString();
     signature_info->setSigningTime(dateStringToTime(time_str)); // Put this information directly in SignatureInfo object
-    time_of_signing.free();
   }
 
   // check if subfilter is supported for signature validation, only detached signatures work for now
-  sig_dict.dictLookup("SubFilter", &subfilterName);
+  Object subfilterName = sig_dict.dictLookup("SubFilter");
   if (subfilterName.isName("adbe.pkcs7.detached") || subfilterName.isName("adbe.pkcs7.sha1")) {
     signature_info->setSubFilterSupport(true);
   }
-
-  subfilterName.free();
-  sig_dict.free();
 }
 
 void FormFieldSignature::hashSignedDataBlock(SignatureHandler *handler, Goffset block_len)
@@ -1505,9 +1455,8 @@
 
   Goffset fileLength = doc->getBaseStream()->getLength();
   for (int i = 0; i < arrayLen/2; i++) {
-    Object offsetObj, lenObj;
-    byte_range.arrayGet(i*2, &offsetObj);
-    byte_range.arrayGet(i*2+1, &lenObj);
+    Object offsetObj = byte_range.arrayGet(i*2);
+    Object lenObj = byte_range.arrayGet(i*2+1);
 
     if (!offsetObj.isIntOrInt64() || !lenObj.isIntOrInt64()) {
       error(errSyntaxError, 0, "Illegal values in ByteRange array");
@@ -1573,50 +1522,41 @@
   defaultAppearance = NULL;
   defaultResources = NULL;
 
-  acroForm->dictLookup("NeedAppearances", &obj1);
+  obj1 = acroForm->dictLookup("NeedAppearances");
   needAppearances = (obj1.isBool() && obj1.getBool());
-  obj1.free();
 
-  if (acroForm->dictLookup("DA", &obj1)->isString())
+  obj1 = acroForm->dictLookup("DA");
+  if (obj1.isString())
     defaultAppearance = obj1.getString()->copy();
-  obj1.free();
 
-  if (acroForm->dictLookup("Q", &obj1)->isInt())
+  obj1 = acroForm->dictLookup("Q");
+  if (obj1.isInt())
     quadding = static_cast<VariableTextQuadding>(obj1.getInt());
-  obj1.free();
 
-  acroForm->dictLookup("DR", &resDict);
+  resDict = acroForm->dictLookup("DR");
   if (resDict.isDict()) {
     // At a minimum, this dictionary shall contain a Font entry
-    if (resDict.dictLookup("Font", &obj1)->isDict())
+    obj1 = resDict.dictLookup("Font");
+    if (obj1.isDict())
       defaultResources = new GfxResources(xref, resDict.getDict(), NULL);
-    obj1.free();
   }
   if (!defaultResources) {
-    resDict.free();
-    resDict.initNull();
+    resDict.setToNull();
   }
 
-  acroForm->dictLookup("Fields", &obj1);
+  obj1 = acroForm->dictLookup("Fields");
   if (obj1.isArray()) {
     Array *array = obj1.getArray();
-    Object obj2;
-    
     for(int i=0; i<array->getLength(); i++) {
-      Object oref;
-      array->get(i, &obj2);
-      array->getNF(i, &oref);
+      Object obj2 = array->get(i);
+      Object oref = array->getNF(i);
       if (!oref.isRef()) {
         error(errSyntaxWarning, -1, "Direct object in rootFields");
-	obj2.free();
-	oref.free();
         continue;
       }
 
       if (!obj2.isDict()) {
         error(errSyntaxWarning, -1, "Reference in Fields array to an invalid or non existent object");
-	obj2.free();
-	oref.free();
 	continue;
       }
 
@@ -1628,32 +1568,24 @@
       std::set<int> usedParents;
       rootFields[numFields++] = createFieldFromDict (&obj2, doc, oref.getRef(), NULL, &usedParents);
 
-      obj2.free();
-      oref.free();
     }
   } else {
     error(errSyntaxError, -1, "Can't get Fields array\n");
   }
-  obj1.free ();
 
-  acroForm->dictLookup("CO", &obj1);
+  obj1 = acroForm->dictLookup("CO");
   if (obj1.isArray()) {
     Array *array = obj1.getArray();
     calculateOrder.reserve(array->getLength());
     for(int i=0; i<array->getLength(); i++) {
-      Object oref;
-      array->getNF(i, &oref);
+      Object oref = array->getNF(i);
       if (!oref.isRef()) {
         error(errSyntaxWarning, -1, "Direct object in CO");
-        oref.free();
         continue;
       }
       calculateOrder.push_back(oref.getRef());
-
-      oref.free();
     }
   }
-  obj1.free ();
 
 #ifdef DEBUG_FORMS
   for (int i = 0; i < numFields; i++)
@@ -1668,54 +1600,43 @@
   gfree (rootFields);
   delete defaultAppearance;
   delete defaultResources;
-  resDict.free();
 }
 
 // Look up an inheritable field dictionary entry.
-static Object *fieldLookup(Dict *field, const char *key, Object *obj, std::set<int> *usedParents) {
-  Dict *dict;
-  Object parent;
-
-  dict = field;
-  if (!dict->lookup(key, obj)->isNull()) {
+static Object fieldLookup(Dict *field, const char *key, std::set<int> *usedParents) {
+  Dict *dict = field;
+  Object obj = dict->lookup(key);
+  if (!obj.isNull()) {
     return obj;
   }
-  obj->free();
-  dict->lookupNF("Parent", &parent);
+  Object parent = dict->lookupNF("Parent");
   if (parent.isRef()) {
     const Ref ref = parent.getRef();
     if (usedParents->find(ref.num) == usedParents->end()) {
       usedParents->insert(ref.num);
 
-      Object obj2;
-      parent.fetch(dict->getXRef(), &obj2);
+      Object obj2 = parent.fetch(dict->getXRef());
       if (obj2.isDict()) {
-        fieldLookup(obj2.getDict(), key, obj, usedParents);
-      } else {
-        obj->initNull();
+        return fieldLookup(obj2.getDict(), key, usedParents);
       }
-      obj2.free();
     }
   } else if (parent.isDict()) {
-    fieldLookup(parent.getDict(), key, obj, usedParents);
-  } else {
-    obj->initNull();
+    return fieldLookup(parent.getDict(), key, usedParents);
   }
-  parent.free();
-  return obj;
+  return Object(objNull);
 }
 
-Object *Form::fieldLookup(Dict *field, const char *key, Object *obj) {
+Object Form::fieldLookup(Dict *field, const char *key) {
   std::set<int> usedParents;
-  return ::fieldLookup(field, key, obj, &usedParents);
+  return ::fieldLookup(field, key, &usedParents);
 }
 
 FormField *Form::createFieldFromDict (Object* obj, PDFDoc *docA, const Ref& pref, FormField *parent, std::set<int> *usedParents)
 {
-    Object obj2;
     FormField *field;
 
-    if (Form::fieldLookup(obj->getDict (), "FT", &obj2)->isName("Btn")) {
+    Object obj2 = Form::fieldLookup(obj->getDict (), "FT");
+    if (obj2.isName("Btn")) {
       field = new FormFieldButton(docA, obj, pref, parent, usedParents);
     } else if (obj2.isName("Tx")) {
       field = new FormFieldText(docA, obj, pref, parent, usedParents);
@@ -1726,7 +1647,6 @@
     } else { //we don't have an FT entry => non-terminal field
       field = new FormField(docA, obj, pref, parent, usedParents);
     }
-    obj2.free();
 
     return field;
 }
diff --git a/poppler/Form.h b/poppler/Form.h
index 8ddb6fe..d73ab89 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -522,7 +522,7 @@
   ~Form();
 
   // Look up an inheritable field dictionary entry.
-  static Object *fieldLookup(Dict *field, const char *key, Object *obj);
+  static Object fieldLookup(Dict *field, const char *key);
   
   /* Creates a new Field of the type specified in obj's dict.
      used in Form::Form and FormField::FormField */
diff --git a/poppler/Function.cc b/poppler/Function.cc
index 785933d..92ba5f7 100644
--- a/poppler/Function.cc
+++ b/poppler/Function.cc
@@ -67,7 +67,6 @@
   Function *func;
   Dict *dict;
   int funcType;
-  Object obj1;
 
   if (funcObj->isStream()) {
     dict = funcObj->streamGetDict();
@@ -80,13 +79,12 @@
     return NULL;
   }
 
-  if (!dict->lookup("FunctionType", &obj1)->isInt()) {
+  Object obj1 = dict->lookup("FunctionType");
+  if (!obj1.isInt()) {
     error(errSyntaxError, -1, "Function type is missing or wrong type");
-    obj1.free();
-    return NULL;
+    return nullptr;
   }
   funcType = obj1.getInt();
-  obj1.free();
 
   if (funcType == 0) {
     func = new SampledFunction(funcObj, dict);
@@ -119,75 +117,65 @@
 }
 
 GBool Function::init(Dict *dict) {
-  Object obj1, obj2;
+  Object obj1;
   int i;
 
   //----- Domain
-  if (!dict->lookup("Domain", &obj1)->isArray()) {
+  obj1 = dict->lookup("Domain");
+  if (!obj1.isArray()) {
     error(errSyntaxError, -1, "Function is missing domain");
-    goto err2;
+    return gFalse;
   }
   m = obj1.arrayGetLength() / 2;
   if (m > funcMaxInputs) {
     error(errSyntaxError, -1, "Functions with more than {0:d} inputs are unsupported",
 	  funcMaxInputs);
-    goto err2;
+    return gFalse;
   }
   for (i = 0; i < m; ++i) {
-    obj1.arrayGet(2*i, &obj2);
+    Object obj2 = obj1.arrayGet(2*i);
     if (!obj2.isNum()) {
       error(errSyntaxError, -1, "Illegal value in function domain array");
-      goto err1;
+      return gFalse;
     }
     domain[i][0] = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(2*i+1, &obj2);
+    obj2 = obj1.arrayGet(2*i+1);
     if (!obj2.isNum()) {
       error(errSyntaxError, -1, "Illegal value in function domain array");
-      goto err1;
+      return gFalse;
     }
     domain[i][1] = obj2.getNum();
-    obj2.free();
   }
-  obj1.free();
 
   //----- Range
   hasRange = gFalse;
   n = 0;
-  if (dict->lookup("Range", &obj1)->isArray()) {
+  obj1 = dict->lookup("Range");
+  if (obj1.isArray()) {
     hasRange = gTrue;
     n = obj1.arrayGetLength() / 2;
     if (n > funcMaxOutputs) {
       error(errSyntaxError, -1, "Functions with more than {0:d} outputs are unsupported",
 	    funcMaxOutputs);
-      goto err2;
+      return gFalse;
     }
     for (i = 0; i < n; ++i) {
-      obj1.arrayGet(2*i, &obj2);
+      Object obj2 = obj1.arrayGet(2*i);
       if (!obj2.isNum()) {
 	error(errSyntaxError, -1, "Illegal value in function range array");
-	goto err1;
+	return gFalse;
       }
       range[i][0] = obj2.getNum();
-      obj2.free();
-      obj1.arrayGet(2*i+1, &obj2);
+      obj2 = obj1.arrayGet(2*i+1);
       if (!obj2.isNum()) {
 	error(errSyntaxError, -1, "Illegal value in function range array");
-	goto err1;
+	return gFalse;
       }
       range[i][1] = obj2.getNum();
-      obj2.free();
     }
   }
-  obj1.free();
 
   return gTrue;
-
- err1:
-  obj2.free();
- err2:
-  obj1.free();
-  return gFalse;
 }
 
 //------------------------------------------------------------------------
@@ -227,7 +215,7 @@
   Stream *str;
   int sampleBits;
   double sampleMul;
-  Object obj1, obj2;
+  Object obj1;
   Guint buf, bitMask;
   int bits;
   Guint s;
@@ -241,16 +229,16 @@
 
   //----- initialize the generic stuff
   if (!init(dict)) {
-    goto err1;
+    return;
   }
   if (!hasRange) {
     error(errSyntaxError, -1, "Type 0 function is missing range");
-    goto err1;
+    return;
   }
   if (m > sampledFuncMaxInputs) {
     error(errSyntaxError, -1, "Sampled functions with more than {0:d} inputs are unsupported",
 	  sampledFuncMaxInputs);
-    goto err1;
+    return;
   }
 
   //----- buffer
@@ -259,30 +247,28 @@
   //----- get the stream
   if (!funcObj->isStream()) {
     error(errSyntaxError, -1, "Type 0 function isn't a stream");
-    goto err1;
+    return;
   }
   str = funcObj->getStream();
 
   //----- Size
-  if (!dict->lookup("Size", &obj1)->isArray() ||
-      obj1.arrayGetLength() != m) {
+  obj1 = dict->lookup("Size");
+  if (!obj1.isArray() || obj1.arrayGetLength() != m) {
     error(errSyntaxError, -1, "Function has missing or invalid size array");
-    goto err2;
+    return;
   }
   for (i = 0; i < m; ++i) {
-    obj1.arrayGet(i, &obj2);
+    Object obj2 = obj1.arrayGet(i);
     if (!obj2.isInt()) {
       error(errSyntaxError, -1, "Illegal value in function size array");
-      goto err3;
+      return;
     }
     sampleSize[i] = obj2.getInt();
     if (sampleSize[i] <= 0) {
       error(errSyntaxError, -1, "Illegal non-positive value in function size array");
-      goto err3;
+      return;
     }
-    obj2.free();
   }
-  obj1.free();
   idxOffset = (int *)gmallocn(1 << m, sizeof(int));
   for (i = 0; i < (1<<m); ++i) {
     idx = 0;
@@ -303,32 +289,30 @@
   }
 
   //----- BitsPerSample
-  if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
+  obj1 = dict->lookup("BitsPerSample");
+  if (!obj1.isInt()) {
     error(errSyntaxError, -1, "Function has missing or invalid BitsPerSample");
-    goto err2;
+    return;
   }
   sampleBits = obj1.getInt();
   sampleMul = 1.0 / (pow(2.0, (double)sampleBits) - 1);
-  obj1.free();
 
   //----- Encode
-  if (dict->lookup("Encode", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 2*m) {
+  obj1 = dict->lookup("Encode");
+  if (obj1.isArray() && obj1.arrayGetLength() == 2*m) {
     for (i = 0; i < m; ++i) {
-      obj1.arrayGet(2*i, &obj2);
+      Object obj2 = obj1.arrayGet(2*i);
       if (!obj2.isNum()) {
 	error(errSyntaxError, -1, "Illegal value in function encode array");
-	goto err3;
+	return;
       }
       encode[i][0] = obj2.getNum();
-      obj2.free();
-      obj1.arrayGet(2*i+1, &obj2);
+      obj2 = obj1.arrayGet(2*i+1);
       if (!obj2.isNum()) {
 	error(errSyntaxError, -1, "Illegal value in function encode array");
-	goto err3;
+	return;
       }
       encode[i][1] = obj2.getNum();
-      obj2.free();
     }
   } else {
     for (i = 0; i < m; ++i) {
@@ -336,30 +320,28 @@
       encode[i][1] = sampleSize[i] - 1;
     }
   }
-  obj1.free();
   for (i = 0; i < m; ++i) {
     inputMul[i] = (encode[i][1] - encode[i][0]) /
                   (domain[i][1] - domain[i][0]);
   }
 
   //----- Decode
-  if (dict->lookup("Decode", &obj1)->isArray() &&
+  obj1 = dict->lookup("Decode");
+  if (obj1.isArray() &&
       obj1.arrayGetLength() == 2*n) {
     for (i = 0; i < n; ++i) {
-      obj1.arrayGet(2*i, &obj2);
+      Object obj2 = obj1.arrayGet(2*i);
       if (!obj2.isNum()) {
 	error(errSyntaxError, -1, "Illegal value in function decode array");
-	goto err3;
+	return;
       }
       decode[i][0] = obj2.getNum();
-      obj2.free();
-      obj1.arrayGet(2*i+1, &obj2);
+      obj2 = obj1.arrayGet(2*i+1);
       if (!obj2.isNum()) {
 	error(errSyntaxError, -1, "Illegal value in function decode array");
-	goto err3;
+	return;
       }
       decode[i][1] = obj2.getNum();
-      obj2.free();
     }
   } else {
     for (i = 0; i < n; ++i) {
@@ -367,7 +349,6 @@
       decode[i][1] = range[i][1];
     }
   }
-  obj1.free();
 
   //----- samples
   nSamples = n;
@@ -409,14 +390,6 @@
   transform(in, cacheOut);
 
   ok = gTrue;
-  return;
-
- err3:
-  obj2.free();
- err2:
-  obj1.free();
- err1:
-  return;
 }
 
 SampledFunction::~SampledFunction() {
@@ -556,92 +529,81 @@
 //------------------------------------------------------------------------
 
 ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
-  Object obj1, obj2;
-  int i;
+  Object obj1;
 
   ok = gFalse;
 
   //----- initialize the generic stuff
   if (!init(dict)) {
-    goto err1;
+    return;
   }
   if (m != 1) {
     error(errSyntaxError, -1, "Exponential function with more than one input");
-    goto err1;
+    return;
   }
 
   //----- C0
-  if (dict->lookup("C0", &obj1)->isArray()) {
+  obj1 = dict->lookup("C0");
+  if (obj1.isArray()) {
     if (hasRange && obj1.arrayGetLength() != n) {
       error(errSyntaxError, -1, "Function's C0 array is wrong length");
-      goto err2;
+      return;
     }
     n = obj1.arrayGetLength();
     if (unlikely(n > funcMaxOutputs)) {
       error(errSyntaxError, -1, "Function's C0 array is wrong length");
       n = funcMaxOutputs;
     }
-    for (i = 0; i < n; ++i) {
-      obj1.arrayGet(i, &obj2);
+    for (int i = 0; i < n; ++i) {
+      Object obj2 = obj1.arrayGet(i);
       if (!obj2.isNum()) {
 	error(errSyntaxError, -1, "Illegal value in function C0 array");
-	goto err3;
+	return;
       }
       c0[i] = obj2.getNum();
-      obj2.free();
     }
   } else {
     if (hasRange && n != 1) {
       error(errSyntaxError, -1, "Function's C0 array is wrong length");
-      goto err2;
+      return;
     }
     n = 1;
     c0[0] = 0;
   }
-  obj1.free();
 
   //----- C1
-  if (dict->lookup("C1", &obj1)->isArray()) {
+  obj1 = dict->lookup("C1");
+  if (obj1.isArray()) {
     if (obj1.arrayGetLength() != n) {
       error(errSyntaxError, -1, "Function's C1 array is wrong length");
-      goto err2;
+      return;
     }
-    for (i = 0; i < n; ++i) {
-      obj1.arrayGet(i, &obj2);
+    for (int i = 0; i < n; ++i) {
+      Object obj2 = obj1.arrayGet(i);
       if (!obj2.isNum()) {
 	error(errSyntaxError, -1, "Illegal value in function C1 array");
-	goto err3;
+	return;
       }
       c1[i] = obj2.getNum();
-      obj2.free();
     }
   } else {
     if (n != 1) {
       error(errSyntaxError, -1, "Function's C1 array is wrong length");
-      goto err2;
+      return;
     }
     c1[0] = 1;
   }
-  obj1.free();
 
   //----- N (exponent)
-  if (!dict->lookup("N", &obj1)->isNum()) {
+  obj1 = dict->lookup("N");
+  if (!obj1.isNum()) {
     error(errSyntaxError, -1, "Function has missing or invalid N");
-    goto err2;
+    return;
   }
   e = obj1.getNum();
-  obj1.free();
 
   isLinear = fabs(e-1.) < 1e-10;
   ok = gTrue;
-  return;
-
- err3:
-  obj2.free();
- err2:
-  obj1.free();
- err1:
-  return;
 }
 
 ExponentialFunction::~ExponentialFunction() {
@@ -685,7 +647,7 @@
 //------------------------------------------------------------------------
 
 StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict, std::set<int> *usedParents) {
-  Object obj1, obj2;
+  Object obj1;
   int i;
 
   ok = gFalse;
@@ -696,17 +658,18 @@
 
   //----- initialize the generic stuff
   if (!init(dict)) {
-    goto err1;
+    return;
   }
   if (m != 1) {
     error(errSyntaxError, -1, "Stitching function with more than one input");
-    goto err1;
+    return;
   }
 
   //----- Functions
-  if (!dict->lookup("Functions", &obj1)->isArray()) {
+  obj1 = dict->lookup("Functions");
+  if (!obj1.isArray()) {
     error(errSyntaxError, -1, "Missing 'Functions' entry in stitching function");
-    goto err1;
+    return;
   }
   k = obj1.arrayGetLength();
   funcs = (Function **)gmallocn(k, sizeof(Function *));
@@ -718,63 +681,58 @@
   }
   for (i = 0; i < k; ++i) {
     std::set<int> usedParentsAux = *usedParents;
-    obj1.arrayGetNF(i, &obj2);
+    Object obj2 = obj1.arrayGetNF(i);
     if (obj2.isRef()) {
       const Ref ref = obj2.getRef();
       if (usedParentsAux.find(ref.num) == usedParentsAux.end()) {
         usedParentsAux.insert(ref.num);
-        obj2.free();
-        obj1.arrayGet(i, &obj2);
+        obj2 = obj1.arrayGet(i);
       } else {
-        goto err2;
+        return;
       }
     }
     if (!(funcs[i] = Function::parse(&obj2, &usedParentsAux))) {
-      goto err2;
+      return;
     }
     if (funcs[i]->getInputSize() != 1 ||
 	(i > 0 && funcs[i]->getOutputSize() != funcs[0]->getOutputSize())) {
       error(errSyntaxError, -1,
 	    "Incompatible subfunctions in stitching function");
-      goto err2;
+      return;
     }
-    obj2.free();
   }
-  obj1.free();
 
   //----- Bounds
-  if (!dict->lookup("Bounds", &obj1)->isArray() ||
-      obj1.arrayGetLength() != k - 1) {
+  obj1 = dict->lookup("Bounds");
+  if (!obj1.isArray() || obj1.arrayGetLength() != k - 1) {
     error(errSyntaxError, -1, "Missing or invalid 'Bounds' entry in stitching function");
-    goto err1;
+    return;
   }
   bounds[0] = domain[0][0];
   for (i = 1; i < k; ++i) {
-    if (!obj1.arrayGet(i - 1, &obj2)->isNum()) {
+    Object obj2 = obj1.arrayGet(i - 1);
+    if (!obj2.isNum()) {
       error(errSyntaxError, -1, "Invalid type in 'Bounds' array in stitching function");
-      goto err2;
+      return;
     }
     bounds[i] = obj2.getNum();
-    obj2.free();
   }
   bounds[k] = domain[0][1];
-  obj1.free();
 
   //----- Encode
-  if (!dict->lookup("Encode", &obj1)->isArray() ||
-      obj1.arrayGetLength() != 2 * k) {
+  obj1 = dict->lookup("Encode");
+  if (!obj1.isArray() || obj1.arrayGetLength() != 2 * k) {
     error(errSyntaxError, -1, "Missing or invalid 'Encode' entry in stitching function");
-    goto err1;
+    return;
   }
   for (i = 0; i < 2 * k; ++i) {
-    if (!obj1.arrayGet(i, &obj2)->isNum()) {
+    Object obj2 = obj1.arrayGet(i);
+    if (!obj2.isNum()) {
       error(errSyntaxError, -1, "Invalid type in 'Encode' array in stitching function");
-      goto err2;
+      return;
     }
     encode[i] = obj2.getNum();
-    obj2.free();
   }
-  obj1.free();
 
   //----- pre-compute the scale factors
   for (i = 0; i < k; ++i) {
@@ -790,11 +748,6 @@
   n = funcs[0]->getOutputSize();
   ok = gTrue;
   return;
-
- err2:
-  obj2.free();
- err1:
-  obj1.free();
 }
 
 StitchingFunction::StitchingFunction(const StitchingFunction *func) : Function(func) {
diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index 3722028..4a9aab5 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -334,61 +334,51 @@
     // build font dictionary
     Dict *resDict = resDictA->copy(xref);
     fonts = NULL;
-    resDict->lookupNF("Font", &obj1);
+    obj1 = resDict->lookupNF("Font");
     if (obj1.isRef()) {
-      obj1.fetch(xref, &obj2);
+      obj2 = obj1.fetch(xref);
       if (obj2.isDict()) {
 	r = obj1.getRef();
 	fonts = new GfxFontDict(xref, &r, obj2.getDict());
       }
-      obj2.free();
     } else if (obj1.isDict()) {
       fonts = new GfxFontDict(xref, NULL, obj1.getDict());
     }
-    obj1.free();
 
     // get XObject dictionary
-    resDict->lookup("XObject", &xObjDict);
+    xObjDict = resDict->lookup("XObject");
 
     // get color space dictionary
-    resDict->lookup("ColorSpace", &colorSpaceDict);
+    colorSpaceDict = resDict->lookup("ColorSpace");
 
     // get pattern dictionary
-    resDict->lookup("Pattern", &patternDict);
+    patternDict = resDict->lookup("Pattern");
 
     // get shading dictionary
-    resDict->lookup("Shading", &shadingDict);
+    shadingDict = resDict->lookup("Shading");
 
     // get graphics state parameter dictionary
-    resDict->lookup("ExtGState", &gStateDict);
+    gStateDict = resDict->lookup("ExtGState");
 
     // get properties dictionary
-    resDict->lookup("Properties", &propertiesDict);
+    propertiesDict = resDict->lookup("Properties");
 
     delete resDict;
   } else {
     fonts = NULL;
-    xObjDict.initNull();
-    colorSpaceDict.initNull();
-    patternDict.initNull();
-    shadingDict.initNull();
-    gStateDict.initNull();
-    propertiesDict.initNull();
+    xObjDict.setToNull();
+    colorSpaceDict.setToNull();
+    patternDict.setToNull();
+    shadingDict.setToNull();
+    gStateDict.setToNull();
+    propertiesDict.setToNull();
   }
 
   next = nextA;
 }
 
 GfxResources::~GfxResources() {
-  if (fonts) {
-    delete fonts;
-  }
-  xObjDict.free();
-  colorSpaceDict.free();
-  patternDict.free();
-  shadingDict.free();
-  gStateDict.free();
-  propertiesDict.free();
+  delete fonts;
 }
 
 GfxFont *GfxResources::lookupFont(char *name) {
@@ -405,75 +395,73 @@
   return NULL;
 }
 
-GBool GfxResources::lookupXObject(char *name, Object *obj) {
+Object GfxResources::lookupXObject(char *name) {
   GfxResources *resPtr;
 
   for (resPtr = this; resPtr; resPtr = resPtr->next) {
     if (resPtr->xObjDict.isDict()) {
-      if (!resPtr->xObjDict.dictLookup(name, obj)->isNull())
-	return gTrue;
-      obj->free();
+      Object obj = resPtr->xObjDict.dictLookup(name);
+      if (!obj.isNull())
+	return obj;
     }
   }
   error(errSyntaxError, -1, "XObject '{0:s}' is unknown", name);
-  return gFalse;
+  return Object(objNull);
 }
 
-GBool GfxResources::lookupXObjectNF(char *name, Object *obj) {
+Object GfxResources::lookupXObjectNF(char *name) {
   GfxResources *resPtr;
 
   for (resPtr = this; resPtr; resPtr = resPtr->next) {
     if (resPtr->xObjDict.isDict()) {
-      if (!resPtr->xObjDict.dictLookupNF(name, obj)->isNull())
-	return gTrue;
-      obj->free();
+      Object obj = resPtr->xObjDict.dictLookupNF(name);
+      if (!obj.isNull())
+	return obj;
     }
   }
   error(errSyntaxError, -1, "XObject '{0:s}' is unknown", name);
-  return gFalse;
+  return Object(objNull);
 }
 
-GBool GfxResources::lookupMarkedContentNF(char *name, Object *obj) {
+Object GfxResources::lookupMarkedContentNF(char *name) {
   GfxResources *resPtr;
 
   for (resPtr = this; resPtr; resPtr = resPtr->next) {
     if (resPtr->propertiesDict.isDict()) {
-      if (!resPtr->propertiesDict.dictLookupNF(name, obj)->isNull())
-	return gTrue;
-      obj->free();
+      Object obj = resPtr->propertiesDict.dictLookupNF(name);
+      if (!obj.isNull())
+	return obj;
     }
   }
   error(errSyntaxError, -1, "Marked Content '{0:s}' is unknown", name);
-  return gFalse;
+  return Object(objNull);
 }
 
-void GfxResources::lookupColorSpace(const char *name, Object *obj) {
+Object GfxResources::lookupColorSpace(const char *name) {
   GfxResources *resPtr;
 
   for (resPtr = this; resPtr; resPtr = resPtr->next) {
     if (resPtr->colorSpaceDict.isDict()) {
-      if (!resPtr->colorSpaceDict.dictLookup(name, obj)->isNull()) {
-	return;
+      Object obj = resPtr->colorSpaceDict.dictLookup(name);
+      if (!obj.isNull()) {
+	return obj;
       }
-      obj->free();
     }
   }
-  obj->initNull();
+  return Object(objNull);
 }
 
 GfxPattern *GfxResources::lookupPattern(char *name, OutputDev *out, GfxState *state) {
   GfxResources *resPtr;
   GfxPattern *pattern;
-  Object obj;
 
   for (resPtr = this; resPtr; resPtr = resPtr->next) {
     if (resPtr->patternDict.isDict()) {
-      if (!resPtr->patternDict.dictLookup(name, &obj)->isNull()) {
+      Object obj = resPtr->patternDict.dictLookup(name);
+      if (!obj.isNull()) {
 	pattern = GfxPattern::parse(resPtr, &obj, out, state);
-	obj.free();
 	return pattern;
       }
-      obj.free();
     }
   }
   error(errSyntaxError, -1, "Unknown pattern '{0:s}'", name);
@@ -483,51 +471,50 @@
 GfxShading *GfxResources::lookupShading(char *name, OutputDev *out, GfxState *state) {
   GfxResources *resPtr;
   GfxShading *shading;
-  Object obj;
 
   for (resPtr = this; resPtr; resPtr = resPtr->next) {
     if (resPtr->shadingDict.isDict()) {
-      if (!resPtr->shadingDict.dictLookup(name, &obj)->isNull()) {
+      Object obj = resPtr->shadingDict.dictLookup(name);
+      if (!obj.isNull()) {
 	shading = GfxShading::parse(resPtr, &obj, out, state);
-	obj.free();
 	return shading;
       }
-      obj.free();
     }
   }
   error(errSyntaxError, -1, "ExtGState '{0:s}' is unknown", name);
   return NULL;
 }
 
-GBool GfxResources::lookupGState(char *name, Object *obj) {
-  if (!lookupGStateNF(name, obj))
-    return gFalse;
+Object GfxResources::lookupGState(char *name) {
+  Object obj = lookupGStateNF(name);
+  if (obj.isNull())
+    return Object(objNull);
 
-  if (!obj->isRef())
-    return gTrue;
+  if (!obj.isRef())
+    return obj;
   
-  const Ref ref = obj->getRef();
-  if (!gStateCache.lookup(ref, obj)->isNull())
-    return gTrue;
-  obj->free();
+  const Ref ref = obj.getRef();
+  obj = gStateCache.lookup(ref);
+  if (!obj.isNull())
+    return obj;
 
-  gStateCache.put(ref)->copy(obj);
-  return gTrue;
+  obj = gStateCache.put(ref)->copy();
+  return obj;
 }
 
-GBool GfxResources::lookupGStateNF(char *name, Object *obj) {
+Object GfxResources::lookupGStateNF(char *name) {
   GfxResources *resPtr;
 
   for (resPtr = this; resPtr; resPtr = resPtr->next) {
     if (resPtr->gStateDict.isDict()) {
-      if (!resPtr->gStateDict.dictLookupNF(name, obj)->isNull()) {
-	return gTrue;
+      Object obj = resPtr->gStateDict.dictLookupNF(name);
+      if (!obj.isNull()) {
+	return obj;
       }
-      obj->free();
     }
   }
   error(errSyntaxError, -1, "ExtGState '{0:s}' is unknown", name);
-  return gFalse;
+  return Object(objNull);
 }
 
 //------------------------------------------------------------------------
@@ -652,17 +639,13 @@
 #endif
 
 void Gfx::initDisplayProfile() {
-   Object catDict;
-   xref->getCatalog(&catDict);
+   Object catDict = xref->getCatalog();
    if (catDict.isDict()) {
-     Object outputIntents;
-     catDict.dictLookup("OutputIntents", &outputIntents);
+     Object outputIntents = catDict.dictLookup("OutputIntents");
      if (outputIntents.isArray() && outputIntents.arrayGetLength() == 1) {
-          Object firstElement;
-          outputIntents.arrayGet(0, &firstElement);
+          Object firstElement = outputIntents.arrayGet(0);
           if (firstElement.isDict()) {
-              Object profile;
-              firstElement.dictLookup("DestOutputProfile", &profile);
+              Object profile = firstElement.dictLookup("DestOutputProfile");
               if (profile.isStream()) {
                 Stream *iccStream = profile.getStream();
                 int length = 0;
@@ -675,13 +658,9 @@
                 }
                 gfree(profBuf);
               }
-              profile.free();
           }
-          firstElement.free();
      }
-     outputIntents.free();
    }
-   catDict.free();
 }
 
 #endif
@@ -708,18 +687,15 @@
 }
 
 void Gfx::display(Object *obj, GBool topLevel) {
-  Object obj2;
   int i;
 
   if (obj->isArray()) {
     for (i = 0; i < obj->arrayGetLength(); ++i) {
-      obj->arrayGet(i, &obj2);
+      Object obj2 = obj->arrayGet(i);
       if (!obj2.isStream()) {
 	error(errSyntaxError, -1, "Weird page contents");
-	obj2.free();
 	return;
       }
-      obj2.free();
     }
   } else if (!obj->isStream()) {
     error(errSyntaxError, -1, "Weird page contents");
@@ -742,7 +718,7 @@
   updateLevel = 1; // make sure even empty pages trigger a call to dump()
   lastAbortCheck = 0;
   numArgs = 0;
-  parser->getObj(&obj);
+  obj = parser->getObj();
   while (!obj.isEOF()) {
     commandAborted = gFalse;
 
@@ -786,9 +762,8 @@
 	}
 	delete timer;
       }
-      obj.free();
       for (i = 0; i < numArgs; ++i)
-	args[i].free();
+	args[i].setToNull(); // Free memory early
       numArgs = 0;
 
       // periodically update display
@@ -817,8 +792,7 @@
 
     // got an argument - save it
     } else if (numArgs < maxArgs) {
-      args[numArgs++] = obj;
-
+      args[numArgs++] = std::move(obj);
     // too many arguments - something is wrong
     } else {
       error(errSyntaxError, getPos(), "Too many args in content stream");
@@ -828,13 +802,11 @@
 	printf("\n");
 	fflush(stdout);
       }
-      obj.free();
     }
 
     // grab the next object
-    parser->getObj(&obj);
+    obj = parser->getObj();
   }
-  obj.free();
 
   // args at end with no command
   if (numArgs > 0) {
@@ -848,8 +820,6 @@
       printf("\n");
       fflush(stdout);
     }
-    for (i = 0; i < numArgs; ++i)
-      args[i].free();
   }
 
   popStateGuard();
@@ -975,7 +945,6 @@
 void Gfx::opSetDash(Object args[], int numArgs) {
   Array *a;
   int length;
-  Object obj;
   double *dash;
   int i;
 
@@ -986,11 +955,10 @@
   } else {
     dash = (double *)gmallocn(length, sizeof(double));
     for (i = 0; i < length; ++i) {
-      a->get(i, &obj);
+      Object obj = a->get(i);
       if (obj.isNum()) {
 	dash[i] = obj.getNum();
       }
-      obj.free();
     }
   }
   state->setLineDash(dash, length, args[1].getNum());
@@ -1023,8 +991,7 @@
 }
 
 void Gfx::opSetExtGState(Object args[], int numArgs) {
-  Object obj1, obj2, obj3, obj4, obj5;
-  Object args2[2];
+  Object obj1, obj2;
   GfxBlendMode mode;
   GBool haveFillOP;
   Function *funcs[4];
@@ -1035,12 +1002,12 @@
   double opac;
   int i;
 
-  if (!res->lookupGState(args[0].getName(), &obj1)) {
+  obj1 = res->lookupGState(args[0].getName());
+  if (obj1.isNull()) {
     return;
   }
   if (!obj1.isDict()) {
     error(errSyntaxError, getPos(), "ExtGState '{0:s}' is wrong type", args[0].getName());
-    obj1.free();
     return;
   }
   if (printCommands) {
@@ -1050,33 +1017,31 @@
   }
 
   // parameters that are also set by individual PDF operators
-  if (obj1.dictLookup("LW", &obj2)->isNum()) {
+  obj2 = obj1.dictLookup("LW");
+  if (obj2.isNum()) {
     opSetLineWidth(&obj2, 1);
   }
-  obj2.free();
-  if (obj1.dictLookup("LC", &obj2)->isInt()) {
+  obj2 = obj1.dictLookup("LC");
+  if (obj2.isInt()) {
     opSetLineCap(&obj2, 1);
   }
-  obj2.free();
-  if (obj1.dictLookup("LJ", &obj2)->isInt()) {
+  obj2 = obj1.dictLookup("LJ");
+  if (obj2.isInt()) {
     opSetLineJoin(&obj2, 1);
   }
-  obj2.free();
-  if (obj1.dictLookup("ML", &obj2)->isNum()) {
+  obj2 = obj1.dictLookup("ML");
+  if (obj2.isNum()) {
     opSetMiterLimit(&obj2, 1);
   }
-  obj2.free();
-  if (obj1.dictLookup("D", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 2) {
-    obj2.arrayGet(0, &args2[0]);
-    obj2.arrayGet(1, &args2[1]);
+  obj2 = obj1.dictLookup("D");
+  if (obj2.isArray() && obj2.arrayGetLength() == 2) {
+    Object args2[2];
+    args2[0] = obj2.arrayGet(0);
+    args2[1] = obj2.arrayGet(1);
     if (args2[0].isArray() && args2[1].isNum()) {
       opSetDash(args2, 2);
     }
-    args2[0].free();
-    args2[1].free();
   }
-  obj2.free();
 #if 0 //~ need to add a new version of GfxResources::lookupFont() that
       //~ takes an indirect ref instead of a name
   if (obj1.dictLookup("Font", &obj2)->isArray() &&
@@ -1091,13 +1056,14 @@
   }
   obj2.free();
 #endif
-  if (obj1.dictLookup("FL", &obj2)->isNum()) {
+  obj2 = obj1.dictLookup("FL");
+  if (obj2.isNum()) {
     opSetFlat(&obj2, 1);
   }
-  obj2.free();
 
   // transparency support: blend mode, fill/stroke opacity
-  if (!obj1.dictLookup("BM", &obj2)->isNull()) {
+  obj2 = obj1.dictLookup("BM");
+  if (!obj2.isNull()) {
     if (state->parseBlendMode(&obj2, &mode)) {
       state->setBlendMode(mode);
       out->updateBlendMode(state);
@@ -1105,27 +1071,27 @@
       error(errSyntaxError, getPos(), "Invalid blend mode in ExtGState");
     }
   }
-  obj2.free();
-  if (obj1.dictLookup("ca", &obj2)->isNum()) {
+  obj2 = obj1.dictLookup("ca");
+  if (obj2.isNum()) {
     opac = obj2.getNum();
     state->setFillOpacity(opac < 0 ? 0 : opac > 1 ? 1 : opac);
     out->updateFillOpacity(state);
   }
-  obj2.free();
-  if (obj1.dictLookup("CA", &obj2)->isNum()) {
+  obj2 = obj1.dictLookup("CA");
+  if (obj2.isNum()) {
     opac = obj2.getNum();
     state->setStrokeOpacity(opac < 0 ? 0 : opac > 1 ? 1 : opac);
     out->updateStrokeOpacity(state);
   }
-  obj2.free();
 
   // fill/stroke overprint, overprint mode
-  if ((haveFillOP = (obj1.dictLookup("op", &obj2)->isBool()))) {
+  obj2 = obj1.dictLookup("op");
+  if ((haveFillOP = obj2.isBool())) {
     state->setFillOverprint(obj2.getBool());
     out->updateFillOverprint(state);
   }
-  obj2.free();
-  if (obj1.dictLookup("OP", &obj2)->isBool()) {
+  obj2 = obj1.dictLookup("OP");
+  if (obj2.isBool()) {
     state->setStrokeOverprint(obj2.getBool());
     out->updateStrokeOverprint(state);
     if (!haveFillOP) {
@@ -1133,24 +1099,23 @@
       out->updateFillOverprint(state);
     }
   }
-  obj2.free();
-  if (obj1.dictLookup("OPM", &obj2)->isInt()) {
+  obj2 = obj1.dictLookup("OPM");
+  if (obj2.isInt()) {
     state->setOverprintMode(obj2.getInt());
     out->updateOverprintMode(state);
   }
-  obj2.free();
 
   // stroke adjust
-  if (obj1.dictLookup("SA", &obj2)->isBool()) {
+  obj2 = obj1.dictLookup("SA");
+  if (obj2.isBool()) {
     state->setStrokeAdjust(obj2.getBool());
     out->updateStrokeAdjust(state);
   }
-  obj2.free();
 
   // transfer function
-  if (obj1.dictLookup("TR2", &obj2)->isNull()) {
-    obj2.free();
-    obj1.dictLookup("TR", &obj2);
+  obj2 = obj1.dictLookup("TR2");
+  if (obj2.isNull()) {
+    obj2 = obj1.dictLookup("TR");
   }
   if (obj2.isName("Default") ||
       obj2.isName("Identity")) {
@@ -1159,9 +1124,8 @@
     out->updateTransfer(state);
   } else if (obj2.isArray() && obj2.arrayGetLength() == 4) {
     for (i = 0; i < 4; ++i) {
-      obj2.arrayGet(i, &obj3);
+      Object obj3 = obj2.arrayGet(i);
       funcs[i] = Function::parse(&obj3);
-      obj3.free();
       if (!funcs[i]) {
 	break;
       }
@@ -1179,80 +1143,81 @@
   } else if (!obj2.isNull()) {
     error(errSyntaxError, getPos(), "Invalid transfer function in ExtGState");
   }
-  obj2.free();
 
   // alpha is shape
-  if (obj1.dictLookup("AIS", &obj2)->isBool()) {
+  obj2 = obj1.dictLookup("AIS");
+  if (obj2.isBool()) {
     state->setAlphaIsShape(obj2.getBool());
     out->updateAlphaIsShape(state);
   }
-  obj2.free();
 
   // text knockout
-  if (obj1.dictLookup("TK", &obj2)->isBool()) {
+  obj2 = obj1.dictLookup("TK");
+  if (obj2.isBool()) {
     state->setTextKnockout(obj2.getBool());
     out->updateTextKnockout(state);
   }
-  obj2.free();
 
   // soft mask
-  if (!obj1.dictLookup("SMask", &obj2)->isNull()) {
+  obj2 = obj1.dictLookup("SMask");
+  if (!obj2.isNull()) {
     if (obj2.isName("None")) {
       out->clearSoftMask(state);
     } else if (obj2.isDict()) {
-      if (obj2.dictLookup("S", &obj3)->isName("Alpha")) {
+      Object obj3 = obj2.dictLookup("S");
+      if (obj3.isName("Alpha")) {
 	alpha = gTrue;
       } else { // "Luminosity"
 	alpha = gFalse;
       }
-      obj3.free();
       funcs[0] = NULL;
-      if (!obj2.dictLookup("TR", &obj3)->isNull()) {
+      obj3 = obj2.dictLookup("TR");
+      if (!obj3.isNull()) {
 	if (obj3.isName("Default") ||
 	    obj3.isName("Identity")) {
 	  funcs[0] = NULL;
 	} else {
 	  funcs[0] = Function::parse(&obj3);
-      if (funcs[0] == NULL ||
-          funcs[0]->getInputSize() != 1 ||
-          funcs[0]->getOutputSize() != 1) {
-	    error(errSyntaxError, getPos(),
+	  if (funcs[0] == NULL ||
+	    funcs[0]->getInputSize() != 1 ||
+	    funcs[0]->getOutputSize() != 1) {
+	      error(errSyntaxError, getPos(),
 		  "Invalid transfer function in soft mask in ExtGState");
-	    delete funcs[0];
-	    funcs[0] = NULL;
+	      delete funcs[0];
+	      funcs[0] = NULL;
 	  }
 	}
       }
-      obj3.free();
-      if ((haveBackdropColor = obj2.dictLookup("BC", &obj3)->isArray())) {
+      obj3 = obj2.dictLookup("BC");
+      if ((haveBackdropColor = obj3.isArray())) {
 	for (i = 0; i < gfxColorMaxComps; ++i) {
 	  backdropColor.c[i] = 0;
 	}
 	for (i = 0; i < obj3.arrayGetLength() && i < gfxColorMaxComps; ++i) {
-	  obj3.arrayGet(i, &obj4);
+	  Object obj4 = obj3.arrayGet(i);
 	  if (obj4.isNum()) {
 	    backdropColor.c[i] = dblToCol(obj4.getNum());
 	  }
-	  obj4.free();
 	}
       }
-      obj3.free();
-      if (obj2.dictLookup("G", &obj3)->isStream()) {
-	if (obj3.streamGetDict()->lookup("Group", &obj4)->isDict()) {
+      obj3 = obj2.dictLookup("G");
+      if (obj3.isStream()) {
+	Object obj4 = obj3.streamGetDict()->lookup("Group");
+	if (obj4.isDict()) {
 	  blendingColorSpace = NULL;
 	  isolated = knockout = gFalse;
-	  if (!obj4.dictLookup("CS", &obj5)->isNull()) {
+	  Object obj5 = obj4.dictLookup("CS");
+	  if (!obj5.isNull()) {
 	    blendingColorSpace = GfxColorSpace::parse(res, &obj5, out, state);
 	  }
-	  obj5.free();
-	  if (obj4.dictLookup("I", &obj5)->isBool()) {
+	  obj5 = obj4.dictLookup("I");
+	  if (obj5.isBool()) {
 	    isolated = obj5.getBool();
 	  }
-	  obj5.free();
-	  if (obj4.dictLookup("K", &obj5)->isBool()) {
+	  obj5 = obj4.dictLookup("K");
+	  if (obj5.isBool()) {
 	    knockout = obj5.getBool();
 	  }
-	  obj5.free();
 	  if (!haveBackdropColor) {
 	    if (blendingColorSpace) {
 	      blendingColorSpace->getDefaultColor(&backdropColor);
@@ -1271,85 +1236,70 @@
 	} else {
 	  error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState - missing group");
 	}
-	obj4.free();
       } else {
 	error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState - missing group");
       }
-      obj3.free();
     } else if (!obj2.isNull()) {
       error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState");
     }
   }
-  obj2.free();
-  if (obj1.dictLookup("Font", &obj2)->isArray()) {
+  obj2 = obj1.dictLookup("Font");
+  if (obj2.isArray()) {
     GfxFont *font;
     if (obj2.arrayGetLength() == 2) {
-      Object fargs0, fargs1;
-
-      obj2.arrayGetNF(0,&fargs0);
-      obj2.arrayGet(1,&fargs1);
+      Object fargs0 = obj2.arrayGetNF(0);
+      Object fargs1 = obj2.arrayGet(1);
       if (fargs0.isRef() && fargs1.isNum()) {
-	Object fobj;
-	Ref r;
-
-	fargs0.fetch(xref, &fobj);
+	Object fobj = fargs0.fetch(xref);
 	if (fobj.isDict()) {
-	  r = fargs0.getRef();
+	  Ref r = fargs0.getRef();
 	  font = GfxFont::makeFont(xref,args[0].getName(),r,fobj.getDict());
 	  state->setFont(font,fargs1.getNum());
 	  fontChanged = gTrue;
 	}
-	fobj.free();
       }
-      fargs0.free();
-      fargs1.free();
     } else {
       error(errSyntaxError, getPos(), "Number of args mismatch for /Font in ExtGState");
     }
   }
-  obj2.free();
-  if (obj1.dictLookup("LW", &obj2)->isNum()) {
+  obj2 = obj1.dictLookup("LW");
+  if (obj2.isNum()) {
     opSetLineWidth(&obj2,1);
   }
-  obj2.free();
-  if (obj1.dictLookup("LC", &obj2)->isInt()) {
+  obj2 = obj1.dictLookup("LC");
+  if (obj2.isInt()) {
     opSetLineCap(&obj2,1);
   }
-  obj2.free();
-  if (obj1.dictLookup("LJ", &obj2)->isInt()) {
+  obj2 = obj1.dictLookup("LJ");
+  if (obj2.isInt()) {
     opSetLineJoin(&obj2,1);
   }
-  obj2.free();
-  if (obj1.dictLookup("ML", &obj2)->isNum()) {
+  obj2 = obj1.dictLookup("ML");
+  if (obj2.isNum()) {
     opSetMiterLimit(&obj2,1);
   }
-  obj2.free();
-  if (obj1.dictLookup("D", &obj2)->isArray()) {
+  obj2 = obj1.dictLookup("D");
+  if (obj2.isArray()) {
     if (obj2.arrayGetLength() == 2) {
       Object dargs[2];
 
-      obj2.arrayGetNF(0,&dargs[0]);
-      obj2.arrayGet(1,&dargs[1]);
+      dargs[0] = obj2.arrayGetNF(0);
+      dargs[1] = obj2.arrayGet(1);
       if (dargs[0].isArray() && dargs[1].isInt()) {
 	opSetDash(dargs,2);
       }
-      dargs[0].free();
-      dargs[1].free();
     } else {
       error(errSyntaxError, getPos(), "Number of args mismatch for /D in ExtGState");
     }
   }
-  obj2.free();
-  if (obj1.dictLookup("RI", &obj2)->isName()) {
+  obj2 = obj1.dictLookup("RI");
+  if (obj2.isName()) {
     opSetRenderingIntent(&obj2,1);
   }
-  obj2.free();
-  if (obj1.dictLookup("FL", &obj2)->isNum()) {
+  obj2 = obj1.dictLookup("FL");
+  if (obj2.isNum()) {
     opSetFlat(&obj2,1);
   }
-  obj2.free();
-
-  obj1.free();
 }
 
 void Gfx::doSoftMask(Object *str, GBool alpha,
@@ -1358,7 +1308,7 @@
 		     Function *transferFunc, GfxColor *backdropColor) {
   Dict *dict, *resDict;
   double m[6], bbox[4];
-  Object obj1, obj2;
+  Object obj1;
   int i;
 
   // check for excessive recursion
@@ -1370,50 +1320,42 @@
   dict = str->streamGetDict();
 
   // check form type
-  dict->lookup("FormType", &obj1);
+  obj1 = dict->lookup("FormType");
   if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
     error(errSyntaxError, getPos(), "Unknown form type");
   }
-  obj1.free();
 
   // get bounding box
-  dict->lookup("BBox", &obj1);
+  obj1 = dict->lookup("BBox");
   if (!obj1.isArray()) {
-    obj1.free();
     error(errSyntaxError, getPos(), "Bad form bounding box");
     return;
   }
   for (i = 0; i < 4; ++i) {
-    obj1.arrayGet(i, &obj2);
+    Object obj2 = obj1.arrayGet(i);
     if (likely(obj2.isNum())) bbox[i] = obj2.getNum();
     else {
-      obj2.free();
-      obj1.free();
       error(errSyntaxError, getPos(), "Bad form bounding box (non number)");
       return;
     }
-    obj2.free();
   }
-  obj1.free();
 
   // get matrix
-  dict->lookup("Matrix", &obj1);
+  obj1 = dict->lookup("Matrix");
   if (obj1.isArray()) {
     for (i = 0; i < 6; ++i) {
-      obj1.arrayGet(i, &obj2);
+      Object obj2 = obj1.arrayGet(i);
       if (likely(obj2.isNum())) m[i] = obj2.getNum();
       else m[i] = 0;
-      obj2.free();
     }
   } else {
     m[0] = 1; m[1] = 0;
     m[2] = 0; m[3] = 1;
     m[4] = 0; m[5] = 0;
   }
-  obj1.free();
 
   // get resources
-  dict->lookup("Resources", &obj1);
+  obj1 = dict->lookup("Resources");
   resDict = obj1.isDict() ? obj1.getDict() : (Dict *)NULL;
 
   // draw it
@@ -1426,7 +1368,6 @@
   if (blendingColorSpace) {
     delete blendingColorSpace;
   }
-  obj1.free();
 }
 
 void Gfx::opSetRenderingIntent(Object args[], int numArgs) {
@@ -1440,17 +1381,15 @@
 void Gfx::opSetFillGray(Object args[], int numArgs) {
   GfxColor color;
   GfxColorSpace *colorSpace = NULL;
-  Object obj;
 
   state->setFillPattern(NULL);
-  res->lookupColorSpace("DefaultGray", &obj);
+  Object obj = res->lookupColorSpace("DefaultGray");
   if (!obj.isNull()) {
     colorSpace = GfxColorSpace::parse(res, &obj, out, state);
   }
   if (colorSpace == NULL) {
     colorSpace = new GfxDeviceGrayColorSpace();
   }
-  obj.free();
   state->setFillColorSpace(colorSpace);
   out->updateFillColorSpace(state);
   color.c[0] = dblToCol(args[0].getNum());
@@ -1461,17 +1400,15 @@
 void Gfx::opSetStrokeGray(Object args[], int numArgs) {
   GfxColor color;
   GfxColorSpace *colorSpace = NULL;
-  Object obj;
 
   state->setStrokePattern(NULL);
-  res->lookupColorSpace("DefaultGray", &obj);
+  Object obj = res->lookupColorSpace("DefaultGray");
   if (!obj.isNull()) {
     colorSpace = GfxColorSpace::parse(res, &obj, out, state);
   }
   if (colorSpace == NULL) {
     colorSpace = new GfxDeviceGrayColorSpace();
   }
-  obj.free();
   state->setStrokeColorSpace(colorSpace);
   out->updateStrokeColorSpace(state);
   color.c[0] = dblToCol(args[0].getNum());
@@ -1482,17 +1419,15 @@
 void Gfx::opSetFillCMYKColor(Object args[], int numArgs) {
   GfxColor color;
   GfxColorSpace *colorSpace = NULL;
-  Object obj;
   int i;
 
-  res->lookupColorSpace("DefaultCMYK", &obj);
+  Object obj = res->lookupColorSpace("DefaultCMYK");
   if (!obj.isNull()) {
     colorSpace = GfxColorSpace::parse(res, &obj, out, state);
   }
   if (colorSpace == NULL) {
     colorSpace = new GfxDeviceCMYKColorSpace();
   }
-  obj.free();
   state->setFillPattern(NULL);
   state->setFillColorSpace(colorSpace);
   out->updateFillColorSpace(state);
@@ -1506,18 +1441,16 @@
 void Gfx::opSetStrokeCMYKColor(Object args[], int numArgs) {
   GfxColor color;
   GfxColorSpace *colorSpace = NULL;
-  Object obj;
   int i;
 
   state->setStrokePattern(NULL);
-  res->lookupColorSpace("DefaultCMYK", &obj);
+  Object obj = res->lookupColorSpace("DefaultCMYK");
   if (!obj.isNull()) {
     colorSpace = GfxColorSpace::parse(res, &obj, out, state);
   }
   if (colorSpace == NULL) {
     colorSpace = new GfxDeviceCMYKColorSpace();
   }
-  obj.free();
   state->setStrokeColorSpace(colorSpace);
   out->updateStrokeColorSpace(state);
   for (i = 0; i < 4; ++i) {
@@ -1528,20 +1461,18 @@
 }
 
 void Gfx::opSetFillRGBColor(Object args[], int numArgs) {
-  Object obj;
   GfxColorSpace *colorSpace = NULL;
   GfxColor color;
   int i;
 
   state->setFillPattern(NULL);
-  res->lookupColorSpace("DefaultRGB", &obj);
+  Object obj = res->lookupColorSpace("DefaultRGB");
   if (!obj.isNull()) {
     colorSpace = GfxColorSpace::parse(res, &obj, out, state);
   }
   if (colorSpace == NULL) {
     colorSpace = new GfxDeviceRGBColorSpace();
   }
-  obj.free();
   state->setFillColorSpace(colorSpace);
   out->updateFillColorSpace(state);
   for (i = 0; i < 3; ++i) {
@@ -1552,20 +1483,18 @@
 }
 
 void Gfx::opSetStrokeRGBColor(Object args[], int numArgs) {
-  Object obj;
   GfxColorSpace *colorSpace = NULL;
   GfxColor color;
   int i;
 
   state->setStrokePattern(NULL);
-  res->lookupColorSpace("DefaultRGB", &obj);
+  Object obj = res->lookupColorSpace("DefaultRGB");
   if (!obj.isNull()) {
     colorSpace = GfxColorSpace::parse(res, &obj, out, state);
   }
   if (colorSpace == NULL) {
     colorSpace = new GfxDeviceRGBColorSpace();
   }
-  obj.free();
   state->setStrokeColorSpace(colorSpace);
   out->updateStrokeColorSpace(state);
   for (i = 0; i < 3; ++i) {
@@ -1576,17 +1505,15 @@
 }
 
 void Gfx::opSetFillColorSpace(Object args[], int numArgs) {
-  Object obj;
   GfxColorSpace *colorSpace;
   GfxColor color;
 
-  res->lookupColorSpace(args[0].getName(), &obj);
+  Object obj = res->lookupColorSpace(args[0].getName());
   if (obj.isNull()) {
     colorSpace = GfxColorSpace::parse(res, &args[0], out, state);
   } else {
     colorSpace = GfxColorSpace::parse(res, &obj, out, state);
   }
-  obj.free();
   if (colorSpace) {
     state->setFillPattern(NULL);
     state->setFillColorSpace(colorSpace);
@@ -1600,18 +1527,16 @@
 }
 
 void Gfx::opSetStrokeColorSpace(Object args[], int numArgs) {
-  Object obj;
   GfxColorSpace *colorSpace;
   GfxColor color;
 
   state->setStrokePattern(NULL);
-  res->lookupColorSpace(args[0].getName(), &obj);
+  Object obj = res->lookupColorSpace(args[0].getName());
   if (obj.isNull()) {
     colorSpace = GfxColorSpace::parse(res, &args[0], out, state);
   } else {
     colorSpace = GfxColorSpace::parse(res, &obj, out, state);
   }
-  obj.free();
   if (colorSpace) {
     state->setStrokeColorSpace(colorSpace);
     out->updateStrokeColorSpace(state);
@@ -3886,7 +3811,6 @@
 
 void Gfx::opShowSpaceText(Object args[], int numArgs) {
   Array *a;
-  Object obj;
   int wMode;
   int i;
 
@@ -3902,7 +3826,7 @@
   wMode = state->getFont()->getWMode();
   a = args[0].getArray();
   for (i = 0; i < a->getLength(); ++i) {
-    a->get(i, &obj);
+    Object obj = a->get(i);
     if (obj.isNum()) {
       // this uses the absolute value of the font size to match
       // Acrobat's behavior
@@ -3921,17 +3845,15 @@
       error(errSyntaxError, getPos(),
         "Element of show/space array must be number or string");
     }
-    obj.free();
   }
   out->endStringOp(state);
   if (!ocState) {
     a = args[0].getArray();
     for (i = 0; i < a->getLength(); ++i) {
-      a->get(i, &obj);
+      Object obj = a->get(i);
       if (obj.isString()) {
 	doIncCharCount(obj.getString());
       }
-      obj.free();
     }
   }
 }
@@ -3947,7 +3869,6 @@
   double x0, y0, x1, y1;
   double oldCTM[6], newCTM[6];
   double *mat;
-  Object charProc;
   Dict *resDict;
   Parser *oldParser;
   GfxState *savedState;
@@ -4031,7 +3952,7 @@
       state->transformDelta(dx, dy, &ddx, &ddy);
       if (!out->beginType3Char(state, curX + riseX, curY + riseY, ddx, ddy,
 			       code, u, uLen)) {
-	((Gfx8BitFont *)font)->getCharProc(code, &charProc);
+	Object charProc = ((Gfx8BitFont *)font)->getCharProc(code);
 	if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
 	  pushResources(resDict);
 	}
@@ -4044,7 +3965,6 @@
 	if (resDict) {
 	  popResources();
 	}
-	charProc.free();
       }
       restoreStateStack(savedState);
       // GfxState::restore() does *not* restore the current position,
@@ -4182,39 +4102,34 @@
 
 void Gfx::opXObject(Object args[], int numArgs) {
   char *name;
-  Object obj1, obj2, obj3, refObj;
-#if OPI_SUPPORT
-  Object opiDict;
-#endif
 
   if (!ocState && !out->needCharCount()) {
     return;
   }
   name = args[0].getName();
-  if (!res->lookupXObject(name, &obj1)) {
+  Object obj1 = res->lookupXObject(name);
+  if (obj1.isNull()) {
     return;
   }
   if (!obj1.isStream()) {
       error(errSyntaxError, getPos(), "XObject '{0:s}' is wrong type", name);
-    obj1.free();
     return;
   }
 
 #if OPI_SUPPORT
-  obj1.streamGetDict()->lookup("OPI", &opiDict);
+  Object opiDict = obj1.streamGetDict()->lookup("OPI");
   if (opiDict.isDict()) {
     out->opiBegin(state, opiDict.getDict());
   }
 #endif
-  obj1.streamGetDict()->lookup("Subtype", &obj2);
+  Object obj2 = obj1.streamGetDict()->lookup("Subtype");
   if (obj2.isName("Image")) {
     if (out->needNonText()) {
-      res->lookupXObjectNF(name, &refObj);
+      Object refObj = res->lookupXObjectNF(name);
       doImage(&refObj, obj1.getStream(), gFalse);
-      refObj.free();
     }
   } else if (obj2.isName("Form")) {
-    res->lookupXObjectNF(name, &refObj);
+    Object refObj = res->lookupXObjectNF(name);
     GBool shouldDoForm = gTrue;
     std::set<int>::iterator drawingFormIt;
     if (refObj.isRef()) {
@@ -4235,9 +4150,8 @@
     if (refObj.isRef() && shouldDoForm) {
       formsDrawing.erase(drawingFormIt);
     }
-    refObj.free();
   } else if (obj2.isName("PS")) {
-    obj1.streamGetDict()->lookup("Level1", &obj3);
+    Object obj3 = obj1.streamGetDict()->lookup("Level1");
     out->psXObject(obj1.getStream(),
 		   obj3.isStream() ? obj3.getStream() : (Stream *)NULL);
   } else if (obj2.isName()) {
@@ -4245,14 +4159,11 @@
   } else {
     error(errSyntaxError, getPos(), "XObject subtype is missing or wrong type");
   }
-  obj2.free();
 #if OPI_SUPPORT
   if (opiDict.isDict()) {
     out->opiEnd(state, opiDict.getDict());
   }
-  opiDict.free();
 #endif
-  obj1.free();
 }
 
 void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
@@ -4265,14 +4176,13 @@
   GBool invert;
   GfxColorSpace *colorSpace, *maskColorSpace;
   GfxImageColorMap *maskColorMap;
-  Object maskObj, smaskObj;
   GBool haveColorKeyMask, haveExplicitMask, haveSoftMask;
   int maskColors[2*gfxColorMaxComps];
   int maskWidth, maskHeight;
   GBool maskInvert;
   GBool maskInterpolate;
   Stream *maskStr;
-  Object obj1, obj2;
+  Object obj1;
   int i, n;
 
   // get info from the stream
@@ -4285,84 +4195,72 @@
 
   // check for optional content key
   if (ref) {
-    dict->lookupNF("OC", &obj1);
+    obj1 = dict->lookupNF("OC");
     if (catalog->getOptContentConfig() && !catalog->getOptContentConfig()->optContentIsVisible(&obj1)) {
-      obj1.free();
       return;
     }
-    obj1.free();
   }
 
   // get size
-  dict->lookup("Width", &obj1);
+  obj1 = dict->lookup("Width");
   if (obj1.isNull()) {
-    obj1.free();
-    dict->lookup("W", &obj1);
+    obj1 = dict->lookup("W");
   }
   if (obj1.isInt())
     width = obj1.getInt();
   else if (obj1.isReal())
     width = (int)obj1.getReal();
   else
-    goto err2;
-  obj1.free();
-  dict->lookup("Height", &obj1);
+    goto err1;
+  obj1 = dict->lookup("Height");
   if (obj1.isNull()) {
-    obj1.free();
-    dict->lookup("H", &obj1);
+    obj1 = dict->lookup("H");
   }
   if (obj1.isInt())
     height = obj1.getInt();
   else if (obj1.isReal())
     height = (int)obj1.getReal();
   else
-    goto err2;
-  obj1.free();
+    goto err1;
 
   if (width < 1 || height < 1)
     goto err1;
 
   // image interpolation
-  dict->lookup("Interpolate", &obj1);
+  obj1 = dict->lookup("Interpolate");
   if (obj1.isNull()) {
-    obj1.free();
-    dict->lookup("I", &obj1);
+    obj1 = dict->lookup("I");
   }
   if (obj1.isBool())
     interpolate = obj1.getBool();
   else
     interpolate = gFalse;
-  obj1.free();
   maskInterpolate = gFalse;
 
   // image or mask?
-  dict->lookup("ImageMask", &obj1);
+  obj1 = dict->lookup("ImageMask");
   if (obj1.isNull()) {
-    obj1.free();
-    dict->lookup("IM", &obj1);
+    obj1 = dict->lookup("IM");
   }
   mask = gFalse;
   if (obj1.isBool())
     mask = obj1.getBool();
   else if (!obj1.isNull())
-    goto err2;
-  obj1.free();
+    goto err1;
 
   // bit depth
   if (bits == 0) {
-    dict->lookup("BitsPerComponent", &obj1);
+    obj1 = dict->lookup("BitsPerComponent");
     if (obj1.isNull()) {
-      obj1.free();
-      dict->lookup("BPC", &obj1);
+      obj1 = dict->lookup("BPC");
     }
     if (obj1.isInt()) {
       bits = obj1.getInt();
     } else if (mask) {
       bits = 1;
     } else {
-      goto err2;
+      goto err1;
     }
-    obj1.free();
   }
 
   // display a mask
@@ -4372,22 +4270,20 @@
     if (bits != 1)
       goto err1;
     invert = gFalse;
-    dict->lookup("Decode", &obj1);
+    obj1 = dict->lookup("Decode");
     if (obj1.isNull()) {
-      obj1.free();
-      dict->lookup("D", &obj1);
+      obj1 = dict->lookup("D");
     }
     if (obj1.isArray()) {
-      obj1.arrayGet(0, &obj2);
+      Object obj2;
+      obj2 = obj1.arrayGet(0);
       // Table 4.39 says /Decode must be [1 0] or [0 1]. Adobe
       // accepts [1.0 0.0] as well.
       if (obj2.isNum() && obj2.getNum() >= 0.9)
 	invert = gTrue;
-      obj2.free();
     } else if (!obj1.isNull()) {
-      goto err2;
+      goto err1;
     }
-    obj1.free();
 
     // if drawing is disabled, skip over inline image data
     if (!ocState || !out->needNonText()) {
@@ -4412,24 +4308,19 @@
     }
 
     // get color space and color map
-    dict->lookup("ColorSpace", &obj1);
+    obj1 = dict->lookup("ColorSpace");
     if (obj1.isNull()) {
-      obj1.free();
-      dict->lookup("CS", &obj1);
+      obj1 = dict->lookup("CS");
     }
     if (obj1.isName() && inlineImg) {
-      res->lookupColorSpace(obj1.getName(), &obj2);
+      Object obj2 = res->lookupColorSpace(obj1.getName());
       if (!obj2.isNull()) {
-	obj1.free();
-	obj1 = obj2;
-      } else {
-	obj2.free();
+	obj1 = std::move(obj2);
       }
     }
     if (!obj1.isNull()) {
-      Object objIntent;
       char *tempIntent = NULL;
-      dict->lookup("Intent", &objIntent);
+      Object objIntent = dict->lookup("Intent");
       if (objIntent.isName()) {
         tempIntent = state->getRenderingIntent();
         if (tempIntent != NULL) {
@@ -4442,48 +4333,38 @@
         state->setRenderingIntent(tempIntent);
         free(tempIntent);
       }
-      objIntent.free();
     } else if (csMode == streamCSDeviceGray) {
-      Object objCS;
-      res->lookupColorSpace("DefaultGray", &objCS);
+      Object objCS = res->lookupColorSpace("DefaultGray");
       if (objCS.isNull()) {
         colorSpace = new GfxDeviceGrayColorSpace();
       } else {
         colorSpace = GfxColorSpace::parse(res, &objCS, out, state);
       }
-      objCS.free();
     } else if (csMode == streamCSDeviceRGB) {
-      Object objCS;
-      res->lookupColorSpace("DefaultRGB", &objCS);
+      Object objCS = res->lookupColorSpace("DefaultRGB");
       if (objCS.isNull()) {
         colorSpace = new GfxDeviceRGBColorSpace();
       } else {
         colorSpace = GfxColorSpace::parse(res, &objCS, out, state);
       }
-      objCS.free();
     } else if (csMode == streamCSDeviceCMYK) {
-      Object objCS;
-      res->lookupColorSpace("DefaultCMYK", &objCS);
+      Object objCS = res->lookupColorSpace("DefaultCMYK");
       if (objCS.isNull()) {
         colorSpace = new GfxDeviceCMYKColorSpace();
       } else {
         colorSpace = GfxColorSpace::parse(res, &objCS, out, state);
       }
-      objCS.free();
     } else {
       colorSpace = NULL;
     }
-    obj1.free();
     if (!colorSpace) {
       goto err1;
     }
-    dict->lookup("Decode", &obj1);
+    obj1 = dict->lookup("Decode");
     if (obj1.isNull()) {
-      obj1.free();
-      dict->lookup("D", &obj1);
+      obj1 = dict->lookup("D");
     }
     GfxImageColorMap colorMap(bits, &obj1, colorSpace);
-    obj1.free();
     if (!colorMap.isOk()) {
       goto err1;
     }
@@ -4494,8 +4375,8 @@
     maskWidth = maskHeight = 0; // make gcc happy
     maskInvert = gFalse; // make gcc happy
     maskColorMap = NULL; // make gcc happy
-    dict->lookup("Mask", &maskObj);
-    dict->lookup("SMask", &smaskObj);
+    Object maskObj = dict->lookup("Mask");
+    Object smaskObj = dict->lookup("SMask");
     if (smaskObj.isStream()) {
       // soft mask
       if (inlineImg) {
@@ -4503,78 +4384,63 @@
       }
       maskStr = smaskObj.getStream();
       maskDict = smaskObj.streamGetDict();
-      maskDict->lookup("Width", &obj1);
+      obj1 = maskDict->lookup("Width");
       if (obj1.isNull()) {
-	obj1.free();
-	maskDict->lookup("W", &obj1);
+	obj1 = maskDict->lookup("W");
       }
       if (!obj1.isInt()) {
-	goto err2;
+	goto err1;
       }
       maskWidth = obj1.getInt();
-      obj1.free();
-      maskDict->lookup("Height", &obj1);
+      obj1 = maskDict->lookup("Height");
       if (obj1.isNull()) {
-	obj1.free();
-	maskDict->lookup("H", &obj1);
+	obj1 = maskDict->lookup("H");
       }
       if (!obj1.isInt()) {
-	goto err2;
+	goto err1;
       }
       maskHeight = obj1.getInt();
-      obj1.free();
-      maskDict->lookup("Interpolate", &obj1);
+      obj1 = maskDict->lookup("Interpolate");
       if (obj1.isNull()) {
-        obj1.free();
-        maskDict->lookup("I", &obj1);
+        obj1 = maskDict->lookup("I");
       }
       if (obj1.isBool())
         maskInterpolate = obj1.getBool();
       else
         maskInterpolate = gFalse;
-      obj1.free();
-      maskDict->lookup("BitsPerComponent", &obj1);
+      obj1 = maskDict->lookup("BitsPerComponent");
       if (obj1.isNull()) {
-	obj1.free();
-	maskDict->lookup("BPC", &obj1);
+	obj1 = maskDict->lookup("BPC");
       }
       if (!obj1.isInt()) {
-	goto err2;
+	goto err1;
       }
       maskBits = obj1.getInt();
-      obj1.free();
-      maskDict->lookup("ColorSpace", &obj1);
+      obj1 = maskDict->lookup("ColorSpace");
       if (obj1.isNull()) {
-	obj1.free();
-	maskDict->lookup("CS", &obj1);
+	obj1 = maskDict->lookup("CS");
       }
       if (obj1.isName()) {
-	res->lookupColorSpace(obj1.getName(), &obj2);
+	Object obj2 = res->lookupColorSpace(obj1.getName());
 	if (!obj2.isNull()) {
-	  obj1.free();
-	  obj1 = obj2;
-	} else {
-	  obj2.free();
+	  obj1 = std::move(obj2);
 	}
       }
       maskColorSpace = GfxColorSpace::parse(NULL, &obj1, out, state);
-      obj1.free();
       if (!maskColorSpace || maskColorSpace->getMode() != csDeviceGray) {
 	goto err1;
       }
-      maskDict->lookup("Decode", &obj1);
+      obj1 = maskDict->lookup("Decode");
       if (obj1.isNull()) {
-	obj1.free();
-	maskDict->lookup("D", &obj1);
+	obj1 = maskDict->lookup("D");
       }
       maskColorMap = new GfxImageColorMap(maskBits, &obj1, maskColorSpace);
-      obj1.free();
       if (!maskColorMap->isOk()) {
 	delete maskColorMap;
 	goto err1;
       }
       // handle the Matte entry
-      maskDict->lookup("Matte", &obj1);
+      obj1 = maskDict->lookup("Matte");
       if (obj1.isArray()) {
         if (obj1.getArray()->getLength() != colorSpace->getNComps()) {
           error(errSyntaxError, -1, "Matte entry should have {0:d} components but has {1:d}",
@@ -4585,29 +4451,26 @@
         } else {
           GfxColor matteColor;
           for (i = 0; i < colorSpace->getNComps(); i++) {
-            obj1.getArray()->get(i, &obj2);
+            Object obj2 = obj1.getArray()->get(i);
             if (!obj2.isNum()) {
-              obj2.free();
               error(errSyntaxError, -1, "Matte entry {0:d} should be a number but it's of type {1:d}", i, obj2.getType());
 
               break;
             }
             matteColor.c[i] = dblToCol(obj2.getNum());
-            obj2.free();
           }
           if (i == colorSpace->getNComps()) {
             maskColorMap->setMatteColor(&matteColor);
           }
         }
       }
-      obj1.free();
       haveSoftMask = gTrue;
     } else if (maskObj.isArray()) {
       // color key mask
       for (i = 0;
 	   i < maskObj.arrayGetLength() && i < 2*gfxColorMaxComps;
 	   ++i) {
-	maskObj.arrayGet(i, &obj1);
+	obj1 = maskObj.arrayGet(i);
 	if (obj1.isInt()) {
 	  maskColors[i] = obj1.getInt();
 	} else if (obj1.isReal()) {
@@ -4615,10 +4478,8 @@
 	  maskColors[i] = (int) obj1.getReal();
 	} else {
 	  error(errSyntaxError, -1, "Mask entry should be an integer but it's of type {0:d}", obj1.getType());
-	  obj1.free();
 	  goto err1;
 	}
-	obj1.free();
       }
       haveColorKeyMask = gTrue;
     } else if (maskObj.isStream()) {
@@ -4628,63 +4489,52 @@
       }
       maskStr = maskObj.getStream();
       maskDict = maskObj.streamGetDict();
-      maskDict->lookup("Width", &obj1);
+      obj1 = maskDict->lookup("Width");
       if (obj1.isNull()) {
-	obj1.free();
-	maskDict->lookup("W", &obj1);
+	obj1 = maskDict->lookup("W");
       }
       if (!obj1.isInt()) {
-	goto err2;
+	goto err1;
       }
       maskWidth = obj1.getInt();
-      obj1.free();
-      maskDict->lookup("Height", &obj1);
+      obj1 = maskDict->lookup("Height");
       if (obj1.isNull()) {
-	obj1.free();
-	maskDict->lookup("H", &obj1);
+	obj1 = maskDict->lookup("H");
       }
       if (!obj1.isInt()) {
-	goto err2;
+	goto err1;
       }
       maskHeight = obj1.getInt();
-      obj1.free();
-      maskDict->lookup("Interpolate", &obj1);
+      obj1 = maskDict->lookup("Interpolate");
       if (obj1.isNull()) {
-        obj1.free();
-	maskDict->lookup("I", &obj1);
+	obj1 = maskDict->lookup("I");
       }
       if (obj1.isBool())
         maskInterpolate = obj1.getBool();
       else
         maskInterpolate = gFalse;
-      obj1.free();
-      maskDict->lookup("ImageMask", &obj1);
+      obj1 = maskDict->lookup("ImageMask");
       if (obj1.isNull()) {
-	obj1.free();
-	maskDict->lookup("IM", &obj1);
+	obj1 = maskDict->lookup("IM");
       }
       if (!obj1.isBool() || !obj1.getBool()) {
-	goto err2;
+	goto err1;
       }
-      obj1.free();
       maskInvert = gFalse;
-      maskDict->lookup("Decode", &obj1);
+      obj1 = maskDict->lookup("Decode");
       if (obj1.isNull()) {
-	obj1.free();
-	maskDict->lookup("D", &obj1);
+	obj1 = maskDict->lookup("D");
       }
       if (obj1.isArray()) {
-	obj1.arrayGet(0, &obj2);
+	Object obj2 = obj1.arrayGet(0);
 	// Table 4.39 says /Decode must be [1 0] or [0 1]. Adobe
 	// accepts [1.0 0.0] as well.
 	if (obj2.isNum() && obj2.getNum() >= 0.9) {
 	  maskInvert = gTrue;
 	}
-	obj2.free();
       } else if (!obj1.isNull()) {
-	goto err2;
+	goto err1;
       }
-      obj1.free();
       haveExplicitMask = gTrue;
     }
 
@@ -4712,9 +4562,6 @@
 		       haveColorKeyMask ? maskColors : (int *)NULL, inlineImg);
       }
     }
-
-    maskObj.free();
-    smaskObj.free();
   }
 
   if ((i = width * height) > 1000) {
@@ -4724,8 +4571,6 @@
 
   return;
 
- err2:
-  obj1.free();
  err1:
   error(errSyntaxError, getPos(), "Bad image parameters");
 }
@@ -4733,22 +4578,22 @@
 GBool Gfx::checkTransparencyGroup(Dict *resDict) {
   // check the effect of compositing objects as a group:
   // look for ExtGState entries with ca != 1 or CA != 1 or BM != normal
-  Object extGStates;
   GBool transpGroup = gFalse;
   double opac;
 
   if (resDict == NULL)
     return gFalse;
   pushResources(resDict);
-  resDict->lookup("ExtGState", &extGStates);
+  Object extGStates = resDict->lookup("ExtGState");
   if (extGStates.isDict()) {
     Dict *dict = extGStates.getDict();
     for (int i = 0; i < dict->getLength() && !transpGroup; i++) {
-      Object obj1, obj2;
       GfxBlendMode mode;
 
-      if (res->lookupGState(dict->getKey(i), &obj1) && obj1.isDict()) {
-        if (!obj1.dictLookup("BM", &obj2)->isNull()) {
+      Object obj1 = res->lookupGState(dict->getKey(i));
+      if (obj1.isDict()) {
+        Object obj2 = obj1.dictLookup("BM");
+        if (!obj2.isNull()) {
           if (state->parseBlendMode(&obj2, &mode)) {
             if (mode != gfxBlendNormal)
               transpGroup = gTrue;
@@ -4756,38 +4601,35 @@
             error(errSyntaxError, getPos(), "Invalid blend mode in ExtGState");
           }
         }
-        obj2.free();
-        if (obj1.dictLookup("ca", &obj2)->isNum()) {
+        obj2 = obj1.dictLookup("ca");
+	if (obj2.isNum()) {
           opac = obj2.getNum();
           opac = opac < 0 ? 0 : opac > 1 ? 1 : opac;
           if (opac != 1)
             transpGroup = gTrue;
         }
-        obj2.free();
-        if (obj1.dictLookup("CA", &obj2)->isNum()) {
+        obj2 = obj1.dictLookup("CA");
+	if (obj2.isNum()) {
           opac = obj2.getNum();
           opac = opac < 0 ? 0 : opac > 1 ? 1 : opac;
           if (opac != 1)
             transpGroup = gTrue;
         }
-        obj2.free();
         // alpha is shape
-        if (!transpGroup && obj1.dictLookup("AIS", &obj2)->isBool()) {
+	obj2 = obj1.dictLookup("AIS");
+        if (!transpGroup && obj2.isBool()) {
           transpGroup = obj2.getBool();
         }
-        obj2.free();
         // soft mask
-        if (!transpGroup && !obj1.dictLookup("SMask", &obj2)->isNull()) {
+	obj2 = obj1.dictLookup("SMask");
+        if (!transpGroup && !obj2.isNull()) {
           if (!obj2.isName("None")) {
             transpGroup = gTrue;
           }
         }
-        obj2.free();
       }
-      obj1.free();
     }
   }
-  extGStates.free();
   popResources();
   return transpGroup;
 }
@@ -4796,12 +4638,10 @@
   Dict *dict;
   GBool transpGroup, isolated, knockout;
   GfxColorSpace *blendingColorSpace;
-  Object matrixObj, bboxObj;
   double m[6], bbox[4];
-  Object resObj;
   Dict *resDict;
   GBool ocSaved;
-  Object obj1, obj2, obj3;
+  Object obj1;
   int i;
 
   // check for excessive recursion
@@ -4813,88 +4653,79 @@
   dict = str->streamGetDict();
 
   // check form type
-  dict->lookup("FormType", &obj1);
+  obj1 = dict->lookup("FormType");
   if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
     error(errSyntaxError, getPos(), "Unknown form type");
   }
-  obj1.free();
 
   // check for optional content key
   ocSaved = ocState;
-  dict->lookupNF("OC", &obj1);
+  obj1 = dict->lookupNF("OC");
   if (catalog->getOptContentConfig() && !catalog->getOptContentConfig()->optContentIsVisible(&obj1)) {
-    obj1.free();
     if (out->needCharCount()) {
       ocState = gFalse;
     } else {
       return;
     }
   }
-  obj1.free();
 
   // get bounding box
-  dict->lookup("BBox", &bboxObj);
+  Object bboxObj = dict->lookup("BBox");
   if (!bboxObj.isArray()) {
-    bboxObj.free();
     error(errSyntaxError, getPos(), "Bad form bounding box");
     ocState = ocSaved;
     return;
   }
   for (i = 0; i < 4; ++i) {
-    bboxObj.arrayGet(i, &obj1);
+    obj1 = bboxObj.arrayGet(i);
     if (likely(obj1.isNum())) {
       bbox[i] = obj1.getNum();
-      obj1.free();
     } else {
-      obj1.free();
       error(errSyntaxError, getPos(), "Bad form bounding box value");
       return;
     }
   }
-  bboxObj.free();
 
   // get matrix
-  dict->lookup("Matrix", &matrixObj);
+  Object matrixObj = dict->lookup("Matrix");
   if (matrixObj.isArray()) {
     for (i = 0; i < 6; ++i) {
-      matrixObj.arrayGet(i, &obj1);
+      obj1 = matrixObj.arrayGet(i);
       if (likely(obj1.isNum())) m[i] = obj1.getNum();
       else m[i] = 0;
-      obj1.free();
     }
   } else {
     m[0] = 1; m[1] = 0;
     m[2] = 0; m[3] = 1;
     m[4] = 0; m[5] = 0;
   }
-  matrixObj.free();
 
   // get resources
-  dict->lookup("Resources", &resObj);
+  Object resObj = dict->lookup("Resources");
   resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
 
   // check for a transparency group
   transpGroup = isolated = knockout = gFalse;
   blendingColorSpace = NULL;
-  if (dict->lookup("Group", &obj1)->isDict()) {
-    if (obj1.dictLookup("S", &obj2)->isName("Transparency")) {
-      if (!obj1.dictLookup("CS", &obj3)->isNull()) {
+  obj1 = dict->lookup("Group");
+  if (obj1.isDict()) {
+    Object obj2 = obj1.dictLookup("S");
+    if (obj2.isName("Transparency")) {
+      Object obj3 = obj1.dictLookup("CS");
+      if (!obj3.isNull()) {
 	blendingColorSpace = GfxColorSpace::parse(res, &obj3, out, state);
       }
-      obj3.free();
-      if (obj1.dictLookup("I", &obj3)->isBool()) {
+      obj3 = obj1.dictLookup("I");
+      if (obj3.isBool()) {
 	isolated = obj3.getBool();
       }
-      obj3.free();
-      if (obj1.dictLookup("K", &obj3)->isBool()) {
+      obj3 = obj1.dictLookup("K");
+      if (obj3.isBool()) {
 	knockout = obj3.getBool();
       }
-      obj3.free();
       transpGroup = isolated || out->checkTransparencyGroup(state, knockout) || checkTransparencyGroup(resDict);
     }
-    obj2.free();
   }
-  obj1.free();
 
   // draw it
   ++formDepth;
@@ -4905,7 +4736,6 @@
   if (blendingColorSpace) {
     delete blendingColorSpace;
   }
-  resObj.free();
 
   ocState = ocSaved;
 }
@@ -5046,45 +4876,37 @@
 }
 
 Stream *Gfx::buildImageStream() {
-  Object dict;
-  Object obj;
   char *key;
   Stream *str;
 
   // build dictionary
-  dict.initDict(xref);
-  parser->getObj(&obj);
+  Object dict(new Dict(xref));
+  Object obj = parser->getObj();
   while (!obj.isCmd("ID") && !obj.isEOF()) {
     if (!obj.isName()) {
       error(errSyntaxError, getPos(), "Inline image dictionary key must be a name object");
-      obj.free();
     } else {
       key = copyString(obj.getName());
-      obj.free();
-      parser->getObj(&obj);
+      obj = parser->getObj();
       if (obj.isEOF() || obj.isError()) {
 	gfree(key);
 	break;
       }
-      dict.dictAdd(key, &obj);
+      dict.dictAdd(key, std::move(obj));
     }
-    parser->getObj(&obj);
+    obj = parser->getObj();
   }
   if (obj.isEOF()) {
     error(errSyntaxError, getPos(), "End of file in inline image");
-    obj.free();
-    dict.free();
     return NULL;
   }
-  obj.free();
 
   // make stream
   if (parser->getStream()) {
-    str = new EmbedStream(parser->getStream(), &dict, gFalse, 0);
-    str = str->addFilters(&dict);
+    str = new EmbedStream(parser->getStream(), std::move(dict), gFalse, 0);
+    str = str->addFilters(str->getDict());
   } else {
     str = NULL;
-    dict.free();
   }
 
   return str;
@@ -5177,27 +4999,25 @@
 	error(errSyntaxError, getPos(), "Unexpected MC Type: {0:d}", args[1].getType());
       }
       char* name1 = args[1].getName();
-      Object markedContent;
       MarkedContentStack *mc = mcStack;
       mc->kind = gfxMCOptionalContent;
-      if ( res->lookupMarkedContentNF( name1, &markedContent ) ) {
+      Object markedContent = res->lookupMarkedContentNF( name1 );
+      if (!markedContent.isNull()) {
         bool visible = contentConfig->optContentIsVisible(&markedContent);
         mc->ocSuppressed = !(visible);
       } else {
 	error(errSyntaxError, getPos(), "DID NOT find {0:s}", name1);
       }
-      markedContent.free();
     } else {
       error(errSyntaxError, getPos(), "insufficient arguments for Marked Content");
     }
   } else if (args[0].isName("Span") && numArgs == 2 && args[1].isDict()) {
-    Object obj;
-    if (args[1].dictLookup("ActualText", &obj)->isString()) {
+    Object obj = args[1].dictLookup("ActualText");
+    if (obj.isString()) {
       out->beginActualText(state, obj.getString());
       MarkedContentStack *mc = mcStack;
       mc->kind = gfxMCActualText;
     }
-    obj.free();
   }
 
   if (printCommands) {
@@ -5271,7 +5091,6 @@
 void Gfx::drawAnnot(Object *str, AnnotBorder *border, AnnotColor *aColor,
 		    double xMin, double yMin, double xMax, double yMax, int rotate) {
   Dict *dict, *resDict;
-  Object matrixObj, bboxObj, resObj, obj1;
   double formXMin, formYMin, formXMax, formYMax;
   double x, y, sx, sy, tx, ty;
   double m[6], bbox[4];
@@ -5319,37 +5138,29 @@
     dict = str->streamGetDict();
 
     // get the form bounding box
-    dict->lookup("BBox", &bboxObj);
+    Object bboxObj = dict->lookup("BBox");
     if (!bboxObj.isArray()) {
-      bboxObj.free();
       error(errSyntaxError, getPos(), "Bad form bounding box");
       return;
     }
     for (i = 0; i < 4; ++i) {
-      bboxObj.arrayGet(i, &obj1);
+      Object obj1 = bboxObj.arrayGet(i);
       if (likely(obj1.isNum())) {
         bbox[i] = obj1.getNum();
-        obj1.free();
       } else {
-        obj1.free();
-        bboxObj.free();
         error(errSyntaxError, getPos(), "Bad form bounding box value");
         return;
       }
     }
-    bboxObj.free();
 
     // get the form matrix
-    dict->lookup("Matrix", &matrixObj);
+    Object matrixObj = dict->lookup("Matrix");
     if (matrixObj.isArray() && matrixObj.arrayGetLength() >= 6) {
       for (i = 0; i < 6; ++i) {
-	matrixObj.arrayGet(i, &obj1);
+	Object obj1 = matrixObj.arrayGet(i);
 	if (likely(obj1.isNum())) {
 	  m[i] = obj1.getNum();
-	  obj1.free();
 	} else {
-	  obj1.free();
-	  matrixObj.free();
 	  error(errSyntaxError, getPos(), "Bad form matrix");
 	  return;
 	}
@@ -5359,7 +5170,6 @@
       m[2] = 0; m[3] = 1;
       m[4] = 0; m[5] = 0;
     }
-    matrixObj.free();
 
     // transform the four corners of the form bbox to default user
     // space, and construct the transformed bbox
@@ -5432,13 +5242,11 @@
     m[5] = m[5] * sy + ty;
 
     // get the resources
-    dict->lookup("Resources", &resObj);
+    Object resObj = dict->lookup("Resources");
     resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
 
     // draw it
     drawForm(str, resDict, m, bbox);
-
-    resObj.free();
   }
 
   // draw the border
diff --git a/poppler/Gfx.h b/poppler/Gfx.h
index a82f9f4..00eaec4 100644
--- a/poppler/Gfx.h
+++ b/poppler/Gfx.h
@@ -17,7 +17,7 @@
 // Copyright (C) 2007 Iñigo Martínez <inigomartinez@gmail.com>
 // Copyright (C) 2008 Brad Hards <bradh@kde.org>
 // Copyright (C) 2008, 2010 Carlos Garcia Campos <carlosgc@gnome.org>
-// Copyright (C) 2009-2013 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2009-2013, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2009, 2010, 2012, 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
 // Copyright (C) 2010 David Benjamin <davidben@mit.edu>
 // Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
@@ -113,14 +113,14 @@
   ~GfxResources();
 
   GfxFont *lookupFont(char *name);
-  GBool lookupXObject(char *name, Object *obj);
-  GBool lookupXObjectNF(char *name, Object *obj);
-  GBool lookupMarkedContentNF(char *name, Object *obj);
-  void lookupColorSpace(const char *name, Object *obj);
+  Object lookupXObject(char *name);
+  Object lookupXObjectNF(char *name);
+  Object lookupMarkedContentNF(char *name);
+  Object lookupColorSpace(const char *name);
   GfxPattern *lookupPattern(char *name, OutputDev *out, GfxState *state);
   GfxShading *lookupShading(char *name, OutputDev *out, GfxState *state);
-  GBool lookupGState(char *name, Object *obj);
-  GBool lookupGStateNF(char *name, Object *obj);
+  Object lookupGState(char *name);
+  Object lookupGStateNF(char *name);
 
   GfxResources *getNext() { return next; }
 
diff --git a/poppler/GfxFont.cc b/poppler/GfxFont.cc
index b59ec06..183f049 100644
--- a/poppler/GfxFont.cc
+++ b/poppler/GfxFont.cc
@@ -210,15 +210,13 @@
   Ref embFontIDA;
   GfxFontType typeA;
   GfxFont *font;
-  Object obj1;
 
   // get base font name
   nameA = NULL;
-  fontDict->lookup("BaseFont", &obj1);
+  Object obj1 = fontDict->lookup("BaseFont");
   if (obj1.isName()) {
     nameA = new GooString(obj1.getName());
   }
-  obj1.free();
 
   // get embedded font ID and font type
   typeA = getFontType(xref, fontDict, &embFontIDA);
@@ -290,14 +288,13 @@
   GfxFontType t, expectedType;
   FoFiIdentifierType fft;
   Dict *fontDict2;
-  Object subtype, fontDesc, obj1, obj2, obj3, obj4;
   GBool isType0, err;
 
   t = fontUnknownType;
   embID->num = embID->gen = -1;
   err = gFalse;
 
-  fontDict->lookup("Subtype", &subtype);
+  Object subtype = fontDict->lookup("Subtype");
   expectedType = fontUnknownType;
   isType0 = gFalse;
   if (subtype.isName("Type1") || subtype.isName("MMType1")) {
@@ -314,44 +311,45 @@
     error(errSyntaxWarning, -1, "Unknown font type: '{0:s}'",
 	  subtype.isName() ? subtype.getName() : "???");
   }
-  subtype.free();
 
   fontDict2 = fontDict;
-  if (fontDict->lookup("DescendantFonts", &obj1)->isArray()) {
+  Object obj1 = fontDict->lookup("DescendantFonts");
+  Object obj2; // Do not move to inside the if
+               // we need it around so that fontDict2 remains valid
+  if (obj1.isArray()) {
     if (obj1.arrayGetLength() == 0) {
       error(errSyntaxWarning, -1, "Empty DescendantFonts array in font");
-      obj2.initNull();
-    } else if (obj1.arrayGet(0, &obj2)->isDict()) {
-      if (!isType0) {
-	error(errSyntaxWarning, -1, "Non-CID font with DescendantFonts array");
-      }
-      fontDict2 = obj2.getDict();
-      fontDict2->lookup("Subtype", &subtype);
-      if (subtype.isName("CIDFontType0")) {
-	if (isType0) {
-	  expectedType = fontCIDType0;
+    } else {
+      obj2 = obj1.arrayGet(0);
+      if (obj2.isDict()) {
+	if (!isType0) {
+	  error(errSyntaxWarning, -1, "Non-CID font with DescendantFonts array");
 	}
-      } else if (subtype.isName("CIDFontType2")) {
-	if (isType0) {
-	  expectedType = fontCIDType2;
+	fontDict2 = obj2.getDict();
+	subtype = fontDict2->lookup("Subtype");
+	if (subtype.isName("CIDFontType0")) {
+	  if (isType0) {
+	    expectedType = fontCIDType0;
+	  }
+	} else if (subtype.isName("CIDFontType2")) {
+	  if (isType0) {
+	    expectedType = fontCIDType2;
+	  }
 	}
       }
-      subtype.free();
     }
-  } else {
-    obj2.initNull();
   }
 
-  if (fontDict2->lookup("FontDescriptor", &fontDesc)->isDict()) {
-    if (fontDesc.dictLookupNF("FontFile", &obj3)->isRef()) {
+  Object fontDesc = fontDict2->lookup("FontDescriptor");
+  if (fontDesc.isDict()) {
+    Object obj3 = fontDesc.dictLookupNF("FontFile");
+    if (obj3.isRef()) {
       *embID = obj3.getRef();
       if (expectedType != fontType1) {
 	err = gTrue;
       }
     }
-    obj3.free();
-    if (embID->num == -1 &&
-	fontDesc.dictLookupNF("FontFile2", &obj3)->isRef()) {
+    if (embID->num == -1 && (obj3 = fontDesc.dictLookupNF("FontFile2"), obj3.isRef())) {
       *embID = obj3.getRef();
       if (isType0) {
 	expectedType = fontCIDType2;
@@ -359,12 +357,11 @@
 	err = gTrue;
       }
     }
-    obj3.free();
-    if (embID->num == -1 &&
-	fontDesc.dictLookupNF("FontFile3", &obj3)->isRef()) {
+    if (embID->num == -1 && (obj3 = fontDesc.dictLookupNF("FontFile3"), obj3.isRef())) {
       *embID = obj3.getRef();
-      if (obj3.fetch(xref, &obj4)->isStream()) {
-	obj4.streamGetDict()->lookup("Subtype", &subtype);
+      Object obj4 = obj3.fetch(xref);
+      if (obj4.isStream()) {
+	subtype = obj4.streamGetDict()->lookup("Subtype");
 	if (subtype.isName("Type1")) {
 	  if (expectedType != fontType1) {
 	    err = gTrue;
@@ -405,18 +402,14 @@
 	  error(errSyntaxError, -1, "Unknown font type '{0:s}'",
 		subtype.isName() ? subtype.getName() : "???");
 	}
-	subtype.free();
       }
-      obj4.free();
     }
-    obj3.free();
   }
-  fontDesc.free();
 
   t = fontUnknownType;
   if (embID->num >= 0) {
-    obj3.initRef(embID->num, embID->gen);
-    obj3.fetch(xref, &obj4);
+    Object obj3(embID->num, embID->gen);
+    Object obj4 = obj3.fetch(xref);
     if (obj4.isStream()) {
       obj4.streamReset();
       fft = FoFiIdentifier::identifyStream(&readFromStream, obj4.getStream());
@@ -447,8 +440,6 @@
 	break;
       }
     }
-    obj4.free();
-    obj3.free();
   }
 
   if (t == fontUnknownType) {
@@ -464,53 +455,46 @@
 	  "Mismatch between font type and embedded font file");
   }
 
-  obj2.free();
-  obj1.free();
-
   return t;
 }
 
 void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
-  Object obj1, obj2, obj3, obj4;
   double t;
-  int i;
 
   // assume Times-Roman by default (for substitution purposes)
   flags = fontSerif;
 
   missingWidth = 0;
 
-  if (fontDict->lookup("FontDescriptor", &obj1)->isDict()) {
+  Object obj1 = fontDict->lookup("FontDescriptor");
+  if (obj1.isDict()) {
 
     // get flags
-    if (obj1.dictLookup("Flags", &obj2)->isInt()) {
+    Object obj2 = obj1.dictLookup("Flags");
+    if (obj2.isInt()) {
       flags = obj2.getInt();
     }
-    obj2.free();
 
     // get name
-    obj1.dictLookup("FontName", &obj2);
+    obj2 = obj1.dictLookup("FontName");
     if (obj2.isName()) {
       embFontName = new GooString(obj2.getName());
     }
-    obj2.free();
     if (embFontName == NULL) {
       // get name with typo
-      obj1.dictLookup("Fontname", &obj2);
+      obj2 = obj1.dictLookup("Fontname");
       if (obj2.isName()) {
         embFontName = new GooString(obj2.getName());
         error(errSyntaxWarning, -1, "The file uses Fontname instead of FontName please notify the creator that the file is broken");
       }
-      obj2.free();
     }
 
     // get family
-    obj1.dictLookup("FontFamily", &obj2);
+    obj2 = obj1.dictLookup("FontFamily");
     if (obj2.isString()) family = new GooString(obj2.getString());
-    obj2.free();
 
     // get stretch
-    obj1.dictLookup("FontStretch", &obj2);
+    obj2 = obj1.dictLookup("FontStretch");
     if (obj2.isName()) {
       if (strcmp(obj2.getName(), "UltraCondensed") == 0) stretch = UltraCondensed;
       else if (strcmp(obj2.getName(), "ExtraCondensed") == 0) stretch = ExtraCondensed;
@@ -523,10 +507,9 @@
       else if (strcmp(obj2.getName(), "UltraExpanded") == 0) stretch = UltraExpanded;
       else error(errSyntaxWarning, -1, "Invalid Font Stretch");
     }
-    obj2.free();
     
     // get weight
-    obj1.dictLookup("FontWeight", &obj2);
+    obj2 = obj1.dictLookup("FontWeight");
     if (obj2.isNum()) {
       if (obj2.getNum() == 100) weight = W100;
       else if (obj2.getNum() == 200) weight = W200;
@@ -539,17 +522,15 @@
       else if (obj2.getNum() == 900) weight = W900;
       else error(errSyntaxWarning, -1, "Invalid Font Weight");
     }
-    obj2.free();
 
     // look for MissingWidth
-    obj1.dictLookup("MissingWidth", &obj2);
+    obj2 = obj1.dictLookup("MissingWidth");
     if (obj2.isNum()) {
       missingWidth = obj2.getNum();
     }
-    obj2.free();
 
     // get Ascent and Descent
-    obj1.dictLookup("Ascent", &obj2);
+    obj2 = obj1.dictLookup("Ascent");
     if (obj2.isNum()) {
       t = 0.001 * obj2.getNum();
       // some broken font descriptors specify a negative ascent
@@ -562,8 +543,7 @@
 	ascent = t;
       }
     }
-    obj2.free();
-    obj1.dictLookup("Descent", &obj2);
+    obj2 = obj1.dictLookup("Descent");
     if (obj2.isNum()) {
       t = 0.001 * obj2.getNum();
       // some broken font descriptors specify a positive descent
@@ -575,36 +555,31 @@
 	descent = t;
       }
     }
-    obj2.free();
 
     // font FontBBox
-    if (obj1.dictLookup("FontBBox", &obj2)->isArray()) {
-      for (i = 0; i < 4 && i < obj2.arrayGetLength(); ++i) {
-	if (obj2.arrayGet(i, &obj3)->isNum()) {
+    obj2 = obj1.dictLookup("FontBBox");
+    if (obj2.isArray()) {
+      for (int i = 0; i < 4 && i < obj2.arrayGetLength(); ++i) {
+	Object obj3 = obj2.arrayGet(i);
+	if (obj3.isNum()) {
 	  fontBBox[i] = 0.001 * obj3.getNum();
 	}
-	obj3.free();
       }
     }
-    obj2.free();
-
   }
-  obj1.free();
 }
 
 CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits,
 					      CharCodeToUnicode *ctu) {
   GooString *buf;
-  Object obj1;
 
-  if (!fontDict->lookup("ToUnicode", &obj1)->isStream()) {
-    obj1.free();
+  Object obj1 = fontDict->lookup("ToUnicode");
+  if (!obj1.isStream()) {
     return NULL;
   }
   buf = new GooString();
   obj1.getStream()->fillGooString(buf);
   obj1.streamClose();
-  obj1.free();
   if (ctu) {
     ctu->mergeCMap(buf, nBits);
   } else {
@@ -620,7 +595,6 @@
   SysFontType sysFontType;
   GooString *path, *base14Name, *substName;
   PSFontParam16 *psFont16;
-  Object refObj, embFontObj;
   int substIdx, fontNum;
   GBool embed;
 
@@ -631,14 +605,12 @@
   //----- embedded font
   if (embFontID.num >= 0) {
     embed = gTrue;
-    refObj.initRef(embFontID.num, embFontID.gen);
-    refObj.fetch(xref, &embFontObj);
+    Object refObj(embFontID.num, embFontID.gen);
+    Object embFontObj = refObj.fetch(xref);
     if (!embFontObj.isStream()) {
       error(errSyntaxError, -1, "Embedded font object is wrong type");
       embed = gFalse;
     }
-    embFontObj.free();
-    refObj.free();
     if (embed) {
       if (ps) {
 	switch (type) {
@@ -894,15 +866,12 @@
 
 char *GfxFont::readEmbFontFile(XRef *xref, int *len) {
   char *buf;
-  Object obj1, obj2;
   Stream *str;
 
-  obj1.initRef(embFontID.num, embFontID.gen);
-  obj1.fetch(xref, &obj2);
+  Object obj1(embFontID.num, embFontID.gen);
+  Object obj2 = obj1.fetch(xref);
   if (!obj2.isStream()) {
     error(errSyntaxError, -1, "Embedded font file is not a stream");
-    obj2.free();
-    obj1.free();
     embFontID.num = -1;
     *len = 0;
     return NULL;
@@ -912,9 +881,6 @@
   buf = (char*)str->toUnsignedChars(len);
   str->close();
 
-  obj2.free();
-  obj1.free();
-
   return buf;
 }
 
@@ -995,24 +961,20 @@
 // Returns gTrue if the font has character names like xx or Axx which
 // should be parsed for hex or decimal values.
 static GBool testForNumericNames(Dict *fontDict, GBool hex) {
-  Object enc, diff, obj;
   GBool numeric = gTrue;
 
-  fontDict->lookup("Encoding", &enc);
+  Object enc = fontDict->lookup("Encoding");
   if (!enc.isDict()) {
-    enc.free();
     return gFalse;
   }
 
-  enc.dictLookup("Differences", &diff);
-  enc.free();
+  Object diff = enc.dictLookup("Differences");
   if (!diff.isArray()) {
-    diff.free();
     return gFalse;
   }
 
   for (int i = 0; i < diff.arrayGetLength() && numeric; ++i) {
-    diff.arrayGet(i, &obj);
+    Object obj = diff.arrayGet(i);
     if (obj.isInt()) {
       // All sequences must start between character codes 0 and 5.
       if (obj.getInt() > 5)
@@ -1024,10 +986,8 @@
     } else {
       numeric = gFalse;
     }
-    obj.free();
   }
 
-  diff.free();
   return numeric;
 }
 
@@ -1052,7 +1012,7 @@
   double mul;
   int firstChar, lastChar;
   Gushort w;
-  Object obj1, obj2, obj3;
+  Object obj1;
   int n, i, a, b, m;
 
   refCnt = 1;
@@ -1130,34 +1090,36 @@
   // get font matrix
   fontMat[0] = fontMat[3] = 1;
   fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0;
-  if (fontDict->lookup("FontMatrix", &obj1)->isArray()) {
+  obj1 = fontDict->lookup("FontMatrix");
+  if (obj1.isArray()) {
     for (i = 0; i < 6 && i < obj1.arrayGetLength(); ++i) {
-      if (obj1.arrayGet(i, &obj2)->isNum()) {
+      Object obj2 = obj1.arrayGet(i);
+      if (obj2.isNum()) {
 	fontMat[i] = obj2.getNum();
       }
-      obj2.free();
     }
   }
-  obj1.free();
 
   // get Type 3 bounding box, font definition, and resources
   if (type == fontType3) {
-    if (fontDict->lookup("FontBBox", &obj1)->isArray()) {
+    obj1 = fontDict->lookup("FontBBox");
+    if (obj1.isArray()) {
       for (i = 0; i < 4 && i < obj1.arrayGetLength(); ++i) {
-	if (obj1.arrayGet(i, &obj2)->isNum()) {
+	Object obj2 = obj1.arrayGet(i);
+	if (obj2.isNum()) {
 	  fontBBox[i] = obj2.getNum();
 	}
-	obj2.free();
       }
     }
-    obj1.free();
-    if (!fontDict->lookup("CharProcs", &charProcs)->isDict()) {
+    charProcs = fontDict->lookup("CharProcs");
+    if (!charProcs.isDict()) {
       error(errSyntaxError, -1,
 	    "Missing or invalid CharProcs dictionary in Type 3 font");
-      charProcs.free();
+      charProcs.setToNull();
     }
-    if (!fontDict->lookup("Resources", &resources)->isDict()) {
-      resources.free();
+    resources = fontDict->lookup("Resources");
+    if (!resources.isDict()) {
+      resources.setToNull();
     }
   }
 
@@ -1180,9 +1142,9 @@
   usesMacRomanEnc = gFalse;
   baseEnc = NULL;
   baseEncFromFontFile = gFalse;
-  fontDict->lookup("Encoding", &obj1);
+  obj1 = fontDict->lookup("Encoding");
   if (obj1.isDict()) {
-    obj1.dictLookup("BaseEncoding", &obj2);
+    Object obj2 = obj1.dictLookup("BaseEncoding");
     if (obj2.isName("MacRomanEncoding")) {
       hasEncoding = gTrue;
       usesMacRomanEnc = gTrue;
@@ -1194,7 +1156,6 @@
       hasEncoding = gTrue;
       baseEnc = winAnsiEncoding;
     }
-    obj2.free();
   } else if (obj1.isName("MacRomanEncoding")) {
     hasEncoding = gTrue;
     usesMacRomanEnc = gTrue;
@@ -1298,13 +1259,13 @@
 
   // merge differences into encoding
   if (obj1.isDict()) {
-    obj1.dictLookup("Differences", &obj2);
+    Object obj2 = obj1.dictLookup("Differences");
     if (obj2.isArray()) {
       encodingName->Set("Custom");
       hasEncoding = gTrue;
       code = 0;
       for (i = 0; i < obj2.arrayGetLength(); ++i) {
-	obj2.arrayGet(i, &obj3);
+	Object obj3 = obj2.arrayGet(i);
 	if (obj3.isInt()) {
 	  code = obj3.getInt();
 	} else if (obj3.isName()) {
@@ -1321,18 +1282,11 @@
 		"Wrong type in font encoding resource differences ({0:s})",
 		obj3.getTypeName());
 	}
-	obj3.free();
       }
     }
-    obj2.free();
   }
-  obj1.free();
-  if (ffT1) {
-    delete ffT1;
-  }
-  if (ffT1C) {
-    delete ffT1C;
-  }
+  delete ffT1;
+  delete ffT1C;
 
   //----- build the mapping to Unicode -----
 
@@ -1450,34 +1404,31 @@
   }
 
   // use widths from font dict, if present
-  fontDict->lookup("FirstChar", &obj1);
+  obj1 = fontDict->lookup("FirstChar");
   firstChar = obj1.isInt() ? obj1.getInt() : 0;
-  obj1.free();
   if (firstChar < 0 || firstChar > 255) {
     firstChar = 0;
   }
-  fontDict->lookup("LastChar", &obj1);
+  obj1 = fontDict->lookup("LastChar");
   lastChar = obj1.isInt() ? obj1.getInt() : 255;
-  obj1.free();
   if (lastChar < 0 || lastChar > 255) {
     lastChar = 255;
   }
   mul = (type == fontType3) ? fontMat[0] : 0.001;
-  fontDict->lookup("Widths", &obj1);
+  obj1 = fontDict->lookup("Widths");
   if (obj1.isArray()) {
     flags |= fontFixedWidth;
     if (obj1.arrayGetLength() < lastChar - firstChar + 1) {
       lastChar = firstChar + obj1.arrayGetLength() - 1;
     }
     for (code = firstChar; code <= lastChar; ++code) {
-      obj1.arrayGet(code - firstChar, &obj2);
+      Object obj2 = obj1.arrayGet(code - firstChar);
       if (obj2.isNum()) {
 	widths[code] = obj2.getNum() * mul;
 	if (fabs(widths[code] - widths[firstChar]) > 0.00001) {
 	  flags &= ~fontFixedWidth;
 	}
       }
-      obj2.free();
     }
 
   // use widths from built-in font
@@ -1523,7 +1474,6 @@
       }
     }
   }
-  obj1.free();
 
   ok = gTrue;
 }
@@ -1537,12 +1487,6 @@
     }
   }
   ctu->decRefCnt();
-  if (charProcs.isDict()) {
-    charProcs.free();
-  }
-  if (resources.isDict()) {
-    resources.free();
-  }
 }
 
 // This function is in part a derived work of the Adobe Glyph Mapping
@@ -1809,13 +1753,12 @@
   return charProcs.isDict() ? charProcs.getDict() : (Dict *)NULL;
 }
 
-Object *Gfx8BitFont::getCharProc(int code, Object *proc) {
+Object Gfx8BitFont::getCharProc(int code) {
   if (enc[code] && charProcs.isDict()) {
-    charProcs.dictLookup(enc[code], proc);
+    return charProcs.dictLookup(enc[code]);
   } else {
-    proc->initNull();
+    return Object(objNull);
   }
-  return proc;
 }
 
 Dict *Gfx8BitFont::getResources() {
@@ -1872,17 +1815,16 @@
   cidToGIDLen = 0;
 
   // get the descendant font
-  if (!fontDict->lookup("DescendantFonts", &obj1)->isArray() ||
-      obj1.arrayGetLength() == 0) {
+  obj1 = fontDict->lookup("DescendantFonts");
+  if (!obj1.isArray() || obj1.arrayGetLength() == 0) {
     error(errSyntaxError, -1, "Missing or empty DescendantFonts entry in Type 0 font");
-    obj1.free();
-    goto err1;
+    return;
   }
-  if (!obj1.arrayGet(0, &desFontDictObj)->isDict()) {
+  desFontDictObj = obj1.arrayGet(0);
+  if (!desFontDictObj.isDict()) {
     error(errSyntaxError, -1, "Bad descendant font in Type 0 font");
-    goto err3;
+    return;
   }
-  obj1.free();
   desFontDict = desFontDictObj.getDict();
 
   // get info from font descriptor
@@ -1891,20 +1833,18 @@
   //----- encoding info -----
 
   // char collection
-  if (!desFontDict->lookup("CIDSystemInfo", &obj1)->isDict()) {
+  obj1 = desFontDict->lookup("CIDSystemInfo");
+  if (!obj1.isDict()) {
     error(errSyntaxError, -1, "Missing CIDSystemInfo dictionary in Type 0 descendant font");
-    goto err3;
+    return;
   }
-  obj1.dictLookup("Registry", &obj2);
-  obj1.dictLookup("Ordering", &obj3);
+  obj2 = obj1.dictLookup("Registry");
+  obj3 = obj1.dictLookup("Ordering");
   if (!obj2.isString() || !obj3.isString()) {
     error(errSyntaxError, -1, "Invalid CIDSystemInfo dictionary in Type 0 descendant font");
-    goto err3;
+    return;
   }
   collection = obj2.getString()->copy()->append('-')->append(obj3.getString());
-  obj3.free();
-  obj2.free();
-  obj1.free();
 
   // look for a ToUnicode CMap
   if (!(ctu = readToUnicodeCMap(fontDict, 16, NULL))) {
@@ -1933,7 +1873,7 @@
 	for (size_t i = 0; i < sizeof(knownCollections)/sizeof(knownCollections[0]); i++) {
 	  if (collection->cmp(knownCollections[i]) == 0) {
 	    error(errSyntaxError, -1, "Missing language pack for '{0:t}' mapping", collection);
-	    goto err2;
+	    return;
 	  }
 	}
 	error(errSyntaxError, -1, "Unknown character collection '{0:t}'",
@@ -1963,14 +1903,14 @@
   }
 
   // encoding (i.e., CMap)
-  if (fontDict->lookup("Encoding", &obj1)->isNull()) {
+  obj1 = fontDict->lookup("Encoding");
+  if (obj1.isNull()) {
     error(errSyntaxError, -1, "Missing Encoding entry in Type 0 font");
-    goto err2;
+    return;
   }
   if (!(cMap = CMap::parse(NULL, collection, &obj1))) {
-    goto err2;
+    return;
   }
-  obj1.free();
   if (cMap->getCMapName()) {
     encodingName->Set(cMap->getCMapName()->getCString());
   } else {
@@ -1979,7 +1919,7 @@
 
   // CIDToGIDMap (for embedded TrueType fonts)
   if (type == fontCIDType2 || type == fontCIDType2OT) {
-    desFontDict->lookup("CIDToGIDMap", &obj1);
+    obj1 = desFontDict->lookup("CIDToGIDMap");
     if (obj1.isStream()) {
       cidToGIDLen = 0;
       i = 64;
@@ -1996,26 +1936,27 @@
     } else if (!obj1.isName("Identity") && !obj1.isNull()) {
       error(errSyntaxError, -1, "Invalid CIDToGIDMap entry in CID font");
     }
-    obj1.free();
   }
 
   //----- character metrics -----
 
   // default char width
-  if (desFontDict->lookup("DW", &obj1)->isInt()) {
+  obj1 = desFontDict->lookup("DW");
+  if (obj1.isInt()) {
     widths.defWidth = obj1.getInt() * 0.001;
   }
-  obj1.free();
 
   // char width exceptions
-  if (desFontDict->lookup("W", &obj1)->isArray()) {
+  obj1 = desFontDict->lookup("W");
+  if (obj1.isArray()) {
     excepsSize = 0;
     i = 0;
     while (i + 1 < obj1.arrayGetLength()) {
-      obj1.arrayGet(i, &obj2);
-      obj1.arrayGet(i + 1, &obj3);
+      obj2 = obj1.arrayGet(i);
+      obj3 = obj1.arrayGet(i + 1);
       if (obj2.isInt() && obj3.isInt() && i + 2 < obj1.arrayGetLength()) {
-	if (obj1.arrayGet(i + 2, &obj4)->isNum()) {
+	obj4 = obj1.arrayGet(i + 2);
+	if (obj4.isNum()) {
 	  if (widths.nExceps == excepsSize) {
 	    excepsSize += 16;
 	    widths.exceps = (GfxFontCIDWidthExcep *)
@@ -2029,7 +1970,6 @@
 	} else {
 	  error(errSyntaxError, -1, "Bad widths array in Type 0 font");
 	}
-	obj4.free();
 	i += 3;
       } else if (obj2.isInt() && obj3.isArray()) {
 	if (widths.nExceps + obj3.arrayGetLength() > excepsSize) {
@@ -2040,7 +1980,8 @@
 	}
 	j = obj2.getInt();
 	for (k = 0; k < obj3.arrayGetLength(); ++k) {
-	  if (obj3.arrayGet(k, &obj4)->isNum()) {
+	  obj4 = obj3.arrayGet(k);
+	  if (obj4.isNum()) {
 	    widths.exceps[widths.nExceps].first = j;
 	    widths.exceps[widths.nExceps].last = j;
 	    widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001;
@@ -2049,46 +1990,43 @@
 	  } else {
 	    error(errSyntaxError, -1, "Bad widths array in Type 0 font");
 	  }
-	  obj4.free();
 	}
 	i += 2;
       } else {
 	error(errSyntaxError, -1, "Bad widths array in Type 0 font");
 	++i;
       }
-      obj3.free();
-      obj2.free();
     }
     std::sort(widths.exceps, widths.exceps + widths.nExceps,
 	      cmpWidthExcepFunctor());
   }
-  obj1.free();
 
   // default metrics for vertical font
-  if (desFontDict->lookup("DW2", &obj1)->isArray() &&
+  obj1 = desFontDict->lookup("DW2");
+  if (obj1.isArray() &&
       obj1.arrayGetLength() == 2) {
-    if (obj1.arrayGet(0, &obj2)->isNum()) {
+    obj2 = obj1.arrayGet(0);
+    if (obj2.isNum()) {
       widths.defVY = obj2.getNum() * 0.001;
     }
-    obj2.free();
-    if (obj1.arrayGet(1, &obj2)->isNum()) {
+    obj2 = obj1.arrayGet(1);
+    if (obj2.isNum()) {
       widths.defHeight = obj2.getNum() * 0.001;
     }
-    obj2.free();
   }
-  obj1.free();
 
   // char metric exceptions for vertical font
-  if (desFontDict->lookup("W2", &obj1)->isArray()) {
+  obj1 = desFontDict->lookup("W2");
+  if (obj1.isArray()) {
     excepsSize = 0;
     i = 0;
     while (i + 1 < obj1.arrayGetLength()) {
-      obj1.arrayGet(i, &obj2);
-      obj1.arrayGet(i+ 1, &obj3);
+      obj2 = obj1.arrayGet(i);
+      obj3 = obj1.arrayGet(i+ 1);
       if (obj2.isInt() && obj3.isInt() && i + 4 < obj1.arrayGetLength()) {
-	if (obj1.arrayGet(i + 2, &obj4)->isNum() &&
-	    obj1.arrayGet(i + 3, &obj5)->isNum() &&
-	    obj1.arrayGet(i + 4, &obj6)->isNum()) {
+	if ((obj4 = obj1.arrayGet(i + 2), obj4.isNum()) &&
+	    (obj5 = obj1.arrayGet(i + 3), obj5.isNum()) &&
+	    (obj6 = obj1.arrayGet(i + 4), obj6.isNum())) {
 	  if (widths.nExcepsV == excepsSize) {
 	    excepsSize += 16;
 	    widths.excepsV = (GfxFontCIDWidthExcepV *)
@@ -2104,9 +2042,6 @@
 	} else {
 	  error(errSyntaxError, -1, "Bad widths (W2) array in Type 0 font");
 	}
-	obj6.free();
-	obj5.free();
-	obj4.free();
 	i += 5;
       } else if (obj2.isInt() && obj3.isArray()) {
 	if (widths.nExcepsV + obj3.arrayGetLength() / 3 > excepsSize) {
@@ -2118,9 +2053,9 @@
 	}
 	j = obj2.getInt();
 	for (k = 0; k < obj3.arrayGetLength(); k += 3) {
-	  if (obj3.arrayGet(k, &obj4)->isNum() &&
-	      obj3.arrayGet(k+1, &obj5)->isNum() &&
-	      obj3.arrayGet(k+2, &obj6)->isNum()) {
+	  if ((obj4 = obj3.arrayGet(k), obj4.isNum()) &&
+	      (obj5 = obj3.arrayGet(k+1), obj5.isNum()) &&
+	      (obj6 = obj3.arrayGet(k+2), obj6.isNum())) {
 	    widths.excepsV[widths.nExcepsV].first = j;
 	    widths.excepsV[widths.nExcepsV].last = j;
 	    widths.excepsV[widths.nExcepsV].height = obj4.getNum() * 0.001;
@@ -2131,34 +2066,18 @@
 	  } else {
 	    error(errSyntaxError, -1, "Bad widths (W2) array in Type 0 font");
 	  }
-	  obj6.free();
-	  obj5.free();
-	  obj4.free();
 	}
 	i += 2;
       } else {
 	error(errSyntaxError, -1, "Bad widths (W2) array in Type 0 font");
 	++i;
       }
-      obj3.free();
-      obj2.free();
     }
     std::sort(widths.excepsV, widths.excepsV + widths.nExcepsV,
 	      cmpWidthExcepVFunctor());
   }
-  obj1.free();
 
-  desFontDictObj.free();
   ok = gTrue;
-  return;
-
- err3:
-  obj3.free();
-  obj2.free();
- err2:
-  obj1.free();
-  desFontDictObj.free();
- err1:;
 }
 
 GfxCIDFont::~GfxCIDFont() {
@@ -2560,14 +2479,13 @@
 
 GfxFontDict::GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict) {
   int i;
-  Object obj1, obj2;
   Ref r;
 
   numFonts = fontDict->getLength();
   fonts = (GfxFont **)gmallocn(numFonts, sizeof(GfxFont *));
   for (i = 0; i < numFonts; ++i) {
-    fontDict->getValNF(i, &obj1);
-    obj1.fetch(xref, &obj2);
+    Object obj1 = fontDict->getValNF(i);
+    Object obj2 = obj1.fetch(xref);
     if (obj2.isDict()) {
       if (obj1.isRef()) {
 	r = obj1.getRef();
@@ -2596,8 +2514,6 @@
       error(errSyntaxError, -1, "font resource is not a dictionary");
       fonts[i] = NULL;
     }
-    obj1.free();
-    obj2.free();
   }
 }
 
diff --git a/poppler/GfxFont.h b/poppler/GfxFont.h
index de7a746..06c1df6 100644
--- a/poppler/GfxFont.h
+++ b/poppler/GfxFont.h
@@ -13,7 +13,7 @@
 // All changes made under the Poppler project to this file are licensed
 // under GPL version 2 or later
 //
-// Copyright (C) 2005, 2008, 2015 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2005, 2008, 2015, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
 // Copyright (C) 2006 Kristian Høgsberg <krh@redhat.com>
 // Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org>
@@ -352,7 +352,7 @@
   Dict *getCharProcs();
 
   // Return the Type 3 CharProc for the character associated with <code>.
-  Object *getCharProc(int code, Object *proc);
+  Object getCharProc(int code);
 
   // Return the Type 3 Resources dictionary, or NULL if none.
   Dict *getResources();
diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index f61f812..b2971ec 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -314,40 +314,34 @@
   if (csObj->isName()) {
     if (csObj->isName("DeviceGray") || csObj->isName("G")) {
       if (res != NULL) {
-        Object objCS;
-        res->lookupColorSpace("DefaultGray", &objCS);
+        Object objCS = res->lookupColorSpace("DefaultGray");
         if (objCS.isNull()) {
           cs = new GfxDeviceGrayColorSpace();
         } else {
           cs = GfxColorSpace::parse(NULL, &objCS, out, state);
         }
-        objCS.free();
       } else {
         cs = new GfxDeviceGrayColorSpace();
       }
     } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
       if (res != NULL) {
-        Object objCS;
-        res->lookupColorSpace("DefaultRGB", &objCS);
+        Object objCS = res->lookupColorSpace("DefaultRGB");
         if (objCS.isNull()) {
           cs = new GfxDeviceRGBColorSpace();
         } else {
           cs = GfxColorSpace::parse(NULL, &objCS, out, state);
         }
-        objCS.free();
       } else {
         cs = new GfxDeviceRGBColorSpace();
       }
     } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
       if (res != NULL) {
-        Object objCS;
-        res->lookupColorSpace("DefaultCMYK", &objCS);
+        Object objCS = res->lookupColorSpace("DefaultCMYK");
         if (objCS.isNull()) {
           cs = new GfxDeviceCMYKColorSpace();
         } else {
           cs = GfxColorSpace::parse(NULL, &objCS, out, state);
         }
-        objCS.free();
       } else {
         cs = new GfxDeviceCMYKColorSpace();
       }
@@ -357,43 +351,37 @@
       error(errSyntaxWarning, -1, "Bad color space '{0:s}'", csObj->getName());
     }
   } else if (csObj->isArray() && csObj->arrayGetLength() > 0) {
-    csObj->arrayGet(0, &obj1);
+    obj1 = csObj->arrayGet(0);
     if (obj1.isName("DeviceGray") || obj1.isName("G")) {
       if (res != NULL) {
-        Object objCS;
-        res->lookupColorSpace("DefaultGray", &objCS);
+        Object objCS = res->lookupColorSpace("DefaultGray");
         if (objCS.isNull()) {
           cs = new GfxDeviceGrayColorSpace();
         } else {
           cs = GfxColorSpace::parse(NULL, &objCS, out, state);
         }
-        objCS.free();
       } else {
         cs = new GfxDeviceGrayColorSpace();
       }
     } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
       if (res != NULL) {
-        Object objCS;
-        res->lookupColorSpace("DefaultRGB", &objCS);
+        Object objCS = res->lookupColorSpace("DefaultRGB");
         if (objCS.isNull()) {
           cs = new GfxDeviceRGBColorSpace();
         } else {
           cs = GfxColorSpace::parse(NULL, &objCS, out, state);
         }
-        objCS.free();
       } else {
         cs = new GfxDeviceRGBColorSpace();
       }
     } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
       if (res != NULL) {
-        Object objCS;
-        res->lookupColorSpace("DefaultCMYK", &objCS);
+        Object objCS = res->lookupColorSpace("DefaultCMYK");
         if (objCS.isNull()) {
           cs = new GfxDeviceCMYKColorSpace();
         } else {
           cs = GfxColorSpace::parse(NULL, &objCS, out, state);
         }
-        objCS.free();
       } else {
         cs = new GfxDeviceCMYKColorSpace();
       }
@@ -416,52 +404,44 @@
     } else {
       error(errSyntaxWarning, -1, "Bad color space");
     }
-    obj1.free();
   } else if (csObj->isDict()) {
-    csObj->dictLookup("ColorSpace", &obj1);
+    obj1 = csObj->dictLookup("ColorSpace");
     if (obj1.isName("DeviceGray")) {
       if (res != NULL) {
-        Object objCS;
-        res->lookupColorSpace("DefaultGray", &objCS);
+        Object objCS = res->lookupColorSpace("DefaultGray");
         if (objCS.isNull()) {
           cs = new GfxDeviceGrayColorSpace();
         } else {
           cs = GfxColorSpace::parse(NULL, &objCS, out, state);
         }
-        objCS.free();
       } else {
         cs = new GfxDeviceGrayColorSpace();
       }
     } else if (obj1.isName("DeviceRGB")) {
       if (res != NULL) {
-        Object objCS;
-        res->lookupColorSpace("DefaultRGB", &objCS);
+        Object objCS = res->lookupColorSpace("DefaultRGB");
         if (objCS.isNull()) {
           cs = new GfxDeviceRGBColorSpace();
         } else {
           cs = GfxColorSpace::parse(NULL, &objCS, out, state);
         }
-        objCS.free();
       } else {
         cs = new GfxDeviceRGBColorSpace();
       }
     } else if (obj1.isName("DeviceCMYK")) {
       if (res != NULL) {
-        Object objCS;
-        res->lookupColorSpace("DefaultCMYK", &objCS);
+        Object objCS = res->lookupColorSpace("DefaultCMYK");
         if (objCS.isNull()) {
           cs = new GfxDeviceCMYKColorSpace();
         } else {
           cs = GfxColorSpace::parse(NULL, &objCS, out, state);
         }
-        objCS.free();
       } else {
         cs = new GfxDeviceCMYKColorSpace();
       }
     } else {
       error(errSyntaxWarning, -1, "Bad color space dict'");
     }
-    obj1.free();
   } else {
     error(errSyntaxWarning, -1, "Bad color space - expected name or array or dict");
   }
@@ -830,52 +810,42 @@
 
 GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr, GfxState *state) {
   GfxCalGrayColorSpace *cs;
-  Object obj1, obj2, obj3;
+  Object obj1, obj2;
 
-  arr->get(1, &obj1);
+  obj1 = arr->get(1);
   if (!obj1.isDict()) {
     error(errSyntaxWarning, -1, "Bad CalGray color space");
-    obj1.free();
     return NULL;
   }
   cs = new GfxCalGrayColorSpace();
-  if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 3) {
-    obj2.arrayGet(0, &obj3);
+  obj2 = obj1.dictLookup("WhitePoint");
+  if (obj2.isArray() && obj2.arrayGetLength() == 3) {
+    Object obj3 = obj2.arrayGet(0);
     if (likely(obj3.isNum()))
       cs->whiteX = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(1, &obj3);
+    obj3 = obj2.arrayGet(1);
     if (likely(obj3.isNum()))
       cs->whiteY = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(2, &obj3);
+    obj3 = obj2.arrayGet(2);
     if (likely(obj3.isNum()))
       cs->whiteZ = obj3.getNum();
-    obj3.free();
   }
-  obj2.free();
-  if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 3) {
-    obj2.arrayGet(0, &obj3);
+  obj2 = obj1.dictLookup("BlackPoint");
+  if (obj2.isArray() && obj2.arrayGetLength() == 3) {
+    Object obj3 = obj2.arrayGet(0);
     if (likely(obj3.isNum()))
       cs->blackX = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(1, &obj3);
+    obj3 = obj2.arrayGet(1);
     if (likely(obj3.isNum()))
       cs->blackY = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(2, &obj3);
+    obj3 = obj2.arrayGet(2);
     if (likely(obj3.isNum()))
       cs->blackZ = obj3.getNum();
-    obj3.free();
   }
-  obj2.free();
-  if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
+  obj2 = obj1.dictLookup("Gamma");
+  if (obj2.isNum()) {
     cs->gamma = obj2.getNum();
   }
-  obj2.free();
-  obj1.free();
 
   cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
 		xyzrgb[0][1] * cs->whiteY +
@@ -1209,75 +1179,59 @@
 
 GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr, GfxState *state) {
   GfxCalRGBColorSpace *cs;
-  Object obj1, obj2, obj3;
+  Object obj1, obj2;
   int i;
 
-  arr->get(1, &obj1);
+  obj1 = arr->get(1);
   if (!obj1.isDict()) {
     error(errSyntaxWarning, -1, "Bad CalRGB color space");
-    obj1.free();
     return NULL;
   }
   cs = new GfxCalRGBColorSpace();
-  if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 3) {
-    obj2.arrayGet(0, &obj3);
+  obj2 = obj1.dictLookup("WhitePoint");
+  if (obj2.isArray() && obj2.arrayGetLength() == 3) {
+    Object obj3 = obj2.arrayGet(0);
     if (likely(obj3.isNum()))
       cs->whiteX = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(1, &obj3);
+    obj3 = obj2.arrayGet(1);
     if (likely(obj3.isNum()))
       cs->whiteY = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(2, &obj3);
+    obj3 = obj2.arrayGet(2);
     if (likely(obj3.isNum()))
       cs->whiteZ = obj3.getNum();
-    obj3.free();
   }
-  obj2.free();
-  if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 3) {
-    obj2.arrayGet(0, &obj3);
+  obj2 = obj1.dictLookup("BlackPoint");
+  if (obj2.isArray() && obj2.arrayGetLength() == 3) {
+    Object obj3 = obj2.arrayGet(0);
     if (likely(obj3.isNum()))
       cs->blackX = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(1, &obj3);
+    obj3 = obj2.arrayGet(1);
     if (likely(obj3.isNum()))
       cs->blackY = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(2, &obj3);
+    obj3 = obj2.arrayGet(2);
     if (likely(obj3.isNum()))
       cs->blackZ = obj3.getNum();
-    obj3.free();
   }
-  obj2.free();
-  if (obj1.dictLookup("Gamma", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 3) {
-    obj2.arrayGet(0, &obj3);
+  obj2 = obj1.dictLookup("Gamma");
+  if (obj2.isArray() && obj2.arrayGetLength() == 3) {
+    Object obj3 = obj2.arrayGet(0);
     if (likely(obj3.isNum()))
       cs->gammaR = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(1, &obj3);
+    obj3 = obj2.arrayGet(1);
     if (likely(obj3.isNum()))
       cs->gammaG = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(2, &obj3);
+    obj3 = obj2.arrayGet(2);
     if (likely(obj3.isNum()))
       cs->gammaB = obj3.getNum();
-    obj3.free();
   }
-  obj2.free();
-  if (obj1.dictLookup("Matrix", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 9) {
+  obj2 = obj1.dictLookup("Matrix");
+  if (obj2.isArray() && obj2.arrayGetLength() == 9) {
     for (i = 0; i < 9; ++i) {
-      obj2.arrayGet(i, &obj3);
+      Object obj3 = obj2.arrayGet(i);
       if (likely(obj3.isNum()))
         cs->mat[i] = obj3.getNum();
-      obj3.free();
     }
   }
-  obj2.free();
-  obj1.free();
 
   cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
 		xyzrgb[0][1] * cs->whiteY +
@@ -1596,58 +1550,43 @@
 
 GfxColorSpace *GfxLabColorSpace::parse(Array *arr, GfxState *state) {
   GfxLabColorSpace *cs;
-  Object obj1, obj2, obj3;
+  Object obj1, obj2;
 
-  arr->get(1, &obj1);
+  obj1 = arr->get(1);
   if (!obj1.isDict()) {
     error(errSyntaxWarning, -1, "Bad Lab color space");
-    obj1.free();
     return NULL;
   }
   cs = new GfxLabColorSpace();
-  if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 3) {
-    obj2.arrayGet(0, &obj3);
+  obj2 = obj1.dictLookup("WhitePoint");
+  if (obj2.isArray() && obj2.arrayGetLength() == 3) {
+    Object obj3 = obj2.arrayGet(0);
     cs->whiteX = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(1, &obj3);
+    obj3 = obj2.arrayGet(1);
     cs->whiteY = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(2, &obj3);
+    obj3 = obj2.arrayGet(2);
     cs->whiteZ = obj3.getNum();
-    obj3.free();
   }
-  obj2.free();
-  if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 3) {
-    obj2.arrayGet(0, &obj3);
+  obj2 = obj1.dictLookup("BlackPoint");
+  if (obj2.isArray() && obj2.arrayGetLength() == 3) {
+    Object obj3 = obj2.arrayGet(0);
     cs->blackX = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(1, &obj3);
+    obj3 = obj2.arrayGet(1);
     cs->blackY = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(2, &obj3);
+    obj3 = obj2.arrayGet(2);
     cs->blackZ = obj3.getNum();
-    obj3.free();
   }
-  obj2.free();
-  if (obj1.dictLookup("Range", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 4) {
-    obj2.arrayGet(0, &obj3);
+  obj2 = obj1.dictLookup("Range");
+  if (obj2.isArray() && obj2.arrayGetLength() == 4) {
+    Object obj3 = obj2.arrayGet(0);
     cs->aMin = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(1, &obj3);
+    obj3 = obj2.arrayGet(1);
     cs->aMax = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(2, &obj3);
+    obj3 = obj2.arrayGet(2);
     cs->bMin = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(3, &obj3);
+    obj3 = obj2.arrayGet(3);
     cs->bMax = obj3.getNum();
-    obj3.free();
   }
-  obj2.free();
-  obj1.free();
 
   cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
 		xyzrgb[0][1] * cs->whiteY +
@@ -1936,14 +1875,13 @@
     error(errSyntaxError, -1, "Bad ICCBased color space");
     return NULL;
   }
-  arr->getNF(1, &obj1);
+  obj1 = arr->getNF(1);
   if (obj1.isRef()) {
     iccProfileStreamA = obj1.getRef();
   } else {
     iccProfileStreamA.num = 0;
     iccProfileStreamA.gen = 0;
   }
-  obj1.free();
 #ifdef USE_CMS
   // check cache
   if (out && iccProfileStreamA.num > 0) {
@@ -1973,28 +1911,26 @@
     }
   }
 #endif
-  arr->get(1, &obj1);
+  obj1 = arr->get(1);
   if (!obj1.isStream()) {
     error(errSyntaxWarning, -1, "Bad ICCBased color space (stream)");
-    obj1.free();
     return NULL;
   }
   dict = obj1.streamGetDict();
-  if (!dict->lookup("N", &obj2)->isInt()) {
+  obj2 = dict->lookup("N");
+  if (!obj2.isInt()) {
     error(errSyntaxWarning, -1, "Bad ICCBased color space (N)");
-    obj2.free();
-    obj1.free();
-    return NULL;
+    return nullptr;
   }
   nCompsA = obj2.getInt();
-  obj2.free();
   if (nCompsA > 4) {
     error(errSyntaxError, -1,
 	  "ICCBased color space with too many ({0:d} > 4) components",
 	  nCompsA);
     nCompsA = 4;
   }
-  if (dict->lookup("Alternate", &obj2)->isNull() ||
+  obj2 = dict->lookup("Alternate");
+  if (obj2.isNull() ||
       !(altA = GfxColorSpace::parse(NULL, &obj2, out, state, recursion + 1))) {
     switch (nCompsA) {
     case 1:
@@ -2008,38 +1944,30 @@
       break;
     default:
       error(errSyntaxWarning, -1, "Bad ICCBased color space - invalid N");
-      obj2.free();
-      obj1.free();
       return NULL;
     }
   }
-  obj2.free();
   if (altA->getNComps() != nCompsA) {
       error(errSyntaxWarning, -1, "Bad ICCBased color space - N doesn't match alt color space");
       delete altA;
-      obj1.free();
       return NULL;
   }
   cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
-  if (dict->lookup("Range", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 2 * nCompsA) {
+  obj2 = dict->lookup("Range");
+  if (obj2.isArray() && obj2.arrayGetLength() == 2 * nCompsA) {
     Object obj4;
     for (i = 0; i < nCompsA; ++i) {
-      obj2.arrayGet(2*i, &obj3);
-      obj2.arrayGet(2*i+1, &obj4);
+      obj3 = obj2.arrayGet(2*i);
+      obj4 = obj2.arrayGet(2*i+1);
       if (obj3.isNum() && obj4.isNum()) {
         cs->rangeMin[i] = obj3.getNum();
         cs->rangeMax[i] = obj4.getNum();
       }
-      obj3.free();
-      obj4.free();
     }
   }
-  obj2.free();
-  obj1.free();
 
 #ifdef USE_CMS
-  arr->get(1, &obj1);
+  obj1 = arr->get(1);
   Guchar *profBuf;
   Stream *iccStream = obj1.getStream();
   int length = 0;
@@ -2099,7 +2027,6 @@
     }
     cmsCloseProfile(hp);
   }
-  obj1.free();
   // put this colorSpace into cache
   if (out && iccProfileStreamA.num > 0) {
     GfxICCBasedColorSpaceKey *k = new GfxICCBasedColorSpaceKey(iccProfileStreamA.num, iccProfileStreamA.gen);
@@ -2581,27 +2508,26 @@
 }
 
 GfxColorSpace *GfxIndexedColorSpace::parse(GfxResources *res, Array *arr, OutputDev *out, GfxState *state, int recursion) {
-  GfxIndexedColorSpace *cs;
   GfxColorSpace *baseA;
   int indexHighA;
   Object obj1;
   char *s;
-  int n, i, j;
+  int i, j;
 
   if (arr->getLength() != 4) {
     error(errSyntaxWarning, -1, "Bad Indexed color space");
-    goto err1;
+    return nullptr;
   }
-  arr->get(1, &obj1);
+  obj1 = arr->get(1);
   if (!(baseA = GfxColorSpace::parse(res, &obj1, out, state, recursion + 1))) {
     error(errSyntaxWarning, -1, "Bad Indexed color space (base color space)");
-    goto err2;
+    return nullptr;
   }
-  obj1.free();
-  if (!arr->get(2, &obj1)->isInt()) {
+  obj1 = arr->get(2);
+  if (!obj1.isInt()) {
     error(errSyntaxWarning, -1, "Bad Indexed color space (hival)");
     delete baseA;
-    goto err2;
+    return nullptr;
   }
   indexHighA = obj1.getInt();
   if (indexHighA < 0 || indexHighA > 255) {
@@ -2614,10 +2540,9 @@
     else indexHighA = 255;
     error(errSyntaxWarning, -1, "Bad Indexed color space (invalid indexHigh value, was {0:d} using {1:d} to try to recover)", previousValue, indexHighA);
   }
-  obj1.free();
-  cs = new GfxIndexedColorSpace(baseA, indexHighA);
-  arr->get(3, &obj1);
-  n = baseA->getNComps();
+  GfxIndexedColorSpace *cs = new GfxIndexedColorSpace(baseA, indexHighA);
+  obj1 = arr->get(3);
+  const int n = baseA->getNComps();
   if (obj1.isStream()) {
     obj1.streamReset();
     for (i = 0; i <= indexHighA; ++i) {
@@ -2643,15 +2568,11 @@
     error(errSyntaxWarning, -1, "Bad Indexed color space (lookup table)");
     goto err3;
   }
-  obj1.free();
   return cs;
 
  err3:
   delete cs;
- err2:
-  obj1.free();
- err1:
-  return NULL;
+  return nullptr;
 }
 
 GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color,
@@ -2856,19 +2777,18 @@
     error(errSyntaxWarning, -1, "Bad Separation color space");
     goto err1;
   }
-  if (!arr->get(1, &obj1)->isName()) {
+  obj1 = arr->get(1);
+  if (!obj1.isName()) {
     error(errSyntaxWarning, -1, "Bad Separation color space (name)");
-    goto err2;
+    goto err1;
   }
   nameA = new GooString(obj1.getName());
-  obj1.free();
-  arr->get(2, &obj1);
+  obj1 = arr->get(2);
   if (!(altA = GfxColorSpace::parse(res, &obj1, out, state, recursion + 1))) {
     error(errSyntaxWarning, -1, "Bad Separation color space (alternate color space)");
     goto err3;
   }
-  obj1.free();
-  arr->get(3, &obj1);
+  obj1 = arr->get(3);
   if (!(funcA = Function::parse(&obj1))) {
     goto err4;
   }
@@ -2876,7 +2796,6 @@
     error(errSyntaxWarning, -1, "Bad SeparationColorSpace function");
     goto err5;
   }
-  obj1.free();
   cs = new GfxSeparationColorSpace(nameA, altA, funcA);
   return cs;
 
@@ -2886,10 +2805,8 @@
   delete altA;
  err3:
   delete nameA;
- err2:
-  obj1.free();
  err1:
-  return NULL;
+  return nullptr;
 }
 
 void GfxSeparationColorSpace::getGray(GfxColor *color, GfxGray *gray) {
@@ -3131,12 +3048,11 @@
 
 //~ handle the 'None' colorant
 GfxColorSpace *GfxDeviceNColorSpace::parse(GfxResources *res, Array *arr, OutputDev *out, GfxState *state, int recursion) {
-  GfxDeviceNColorSpace *cs;
   int nCompsA;
   GooString *namesA[gfxColorMaxComps];
   GfxColorSpace *altA;
   Function *funcA;
-  Object obj1, obj2;
+  Object obj1;
   int i;
   GooList *separationList = new GooList();
 
@@ -3144,9 +3060,10 @@
     error(errSyntaxWarning, -1, "Bad DeviceN color space");
     goto err1;
   }
-  if (!arr->get(1, &obj1)->isArray()) {
+  obj1 = arr->get(1);
+  if (!obj1.isArray()) {
     error(errSyntaxWarning, -1, "Bad DeviceN color space (names)");
-    goto err2;
+    goto err1;
   }
   nCompsA = obj1.arrayGetLength();
   if (nCompsA > gfxColorMaxComps) {
@@ -3155,63 +3072,53 @@
     nCompsA = gfxColorMaxComps;
   }
   for (i = 0; i < nCompsA; ++i) {
-    if (!obj1.arrayGet(i, &obj2)->isName()) {
+    Object obj2 = obj1.arrayGet(i);
+    if (!obj2.isName()) {
       error(errSyntaxWarning, -1, "Bad DeviceN color space (names)");
-      obj2.free();
-      goto err2;
+      goto err1;
     }
     namesA[i] = new GooString(obj2.getName());
-    obj2.free();
   }
-  obj1.free();
-  arr->get(2, &obj1);
+  obj1 = arr->get(2);
   if (!(altA = GfxColorSpace::parse(res, &obj1, out, state, recursion + 1))) {
     error(errSyntaxWarning, -1, "Bad DeviceN color space (alternate color space)");
     goto err3;
   }
-  obj1.free();
-  arr->get(3, &obj1);
+  obj1 = arr->get(3);
   if (!(funcA = Function::parse(&obj1))) {
     goto err4;
   }
-  obj1.free();
   if (arr->getLength() == 5) {
-    if (!arr->get(4, &obj1)->isDict()) {
+    obj1 = arr->get(4);
+    if (!obj1.isDict()) {
       error(errSyntaxWarning, -1, "Bad DeviceN color space (attributes)");
-      goto err4;
+      goto err5;
     }
     Dict *attribs = obj1.getDict();
-    attribs->lookup("Colorants", &obj2);
+    Object obj2 = attribs->lookup("Colorants");
     if (obj2.isDict()) {
       Dict *colorants = obj2.getDict();
       for (i = 0; i < colorants->getLength(); i++) {
-        Object obj3;
-        colorants->getVal(i, &obj3);
+        Object obj3 = colorants->getVal(i);
         if (obj3.isArray()) {
           separationList->append(GfxSeparationColorSpace::parse(res, obj3.getArray(), out, state, recursion));
         } else {
-          obj3.free();
-          obj2.free();
           error(errSyntaxWarning, -1, "Bad DeviceN color space (colorant value entry is not an Array)");
-          goto err4;
+          goto err5;
         }
-        obj3.free();
       }
     }
-    obj2.free();
-    obj1.free();
   }
-  cs = new GfxDeviceNColorSpace(nCompsA, namesA, altA, funcA, separationList);
-  return cs;
+  return new GfxDeviceNColorSpace(nCompsA, namesA, altA, funcA, separationList);
 
+ err5:
+  delete funcA;
  err4:
   delete altA;
  err3:
   for (i = 0; i < nCompsA; ++i) {
     delete namesA[i];
   }
- err2:
-  obj1.free();
  err1:
   delete separationList;
   return NULL;
@@ -3407,13 +3314,11 @@
   }
   underA = NULL;
   if (arr->getLength() == 2) {
-    arr->get(1, &obj1);
+    obj1 = arr->get(1);
     if (!(underA = GfxColorSpace::parse(res, &obj1, out, state, recursion + 1))) {
       error(errSyntaxWarning, -1, "Bad Pattern color space (underlying color space)");
-      obj1.free();
       return NULL;
     }
-    obj1.free();
   }
   cs = new GfxPatternColorSpace(underA);
   return cs;
@@ -3458,11 +3363,11 @@
   Object obj1;
 
   if (obj->isDict()) {
-    obj->dictLookup("PatternType", &obj1);
+    obj1 = obj->dictLookup("PatternType");
   } else if (obj->isStream()) {
-    obj->streamGetDict()->lookup("PatternType", &obj1);
+    obj1 = obj->streamGetDict()->lookup("PatternType");
   } else {
-    return NULL;
+    return nullptr;
   }
   pattern = NULL;
   if (obj1.isInt() && obj1.getInt() == 1) {
@@ -3470,7 +3375,6 @@
   } else if (obj1.isInt() && obj1.getInt() == 2) {
     pattern = GfxShadingPattern::parse(res, obj, out, state);
   }
-  obj1.free();
   return pattern;
 }
 
@@ -3479,13 +3383,12 @@
 //------------------------------------------------------------------------
 
 GfxTilingPattern *GfxTilingPattern::parse(Object *patObj) {
-  GfxTilingPattern *pat;
   Dict *dict;
   int paintTypeA, tilingTypeA;
   double bboxA[4], matrixA[6];
   double xStepA, yStepA;
   Object resDictA;
-  Object obj1, obj2;
+  Object obj1;
   int i;
 
   if (!patObj->isStream()) {
@@ -3493,71 +3396,66 @@
   }
   dict = patObj->streamGetDict();
 
-  if (dict->lookup("PaintType", &obj1)->isInt()) {
+  obj1 = dict->lookup("PaintType");
+  if (obj1.isInt()) {
     paintTypeA = obj1.getInt();
   } else {
     paintTypeA = 1;
     error(errSyntaxWarning, -1, "Invalid or missing PaintType in pattern");
   }
-  obj1.free();
-  if (dict->lookup("TilingType", &obj1)->isInt()) {
+  obj1 = dict->lookup("TilingType");
+  if (obj1.isInt()) {
     tilingTypeA = obj1.getInt();
   } else {
     tilingTypeA = 1;
     error(errSyntaxWarning, -1, "Invalid or missing TilingType in pattern");
   }
-  obj1.free();
   bboxA[0] = bboxA[1] = 0;
   bboxA[2] = bboxA[3] = 1;
-  if (dict->lookup("BBox", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 4) {
+  obj1 = dict->lookup("BBox");
+  if (obj1.isArray() && obj1.arrayGetLength() == 4) {
     for (i = 0; i < 4; ++i) {
-      if (obj1.arrayGet(i, &obj2)->isNum()) {
+      Object obj2 = obj1.arrayGet(i);
+      if (obj2.isNum()) {
 	bboxA[i] = obj2.getNum();
       }
-      obj2.free();
     }
   } else {
     error(errSyntaxWarning, -1, "Invalid or missing BBox in pattern");
   }
-  obj1.free();
-  if (dict->lookup("XStep", &obj1)->isNum()) {
+  obj1 = dict->lookup("XStep");
+  if (obj1.isNum()) {
     xStepA = obj1.getNum();
   } else {
     xStepA = 1;
     error(errSyntaxWarning, -1, "Invalid or missing XStep in pattern");
   }
-  obj1.free();
-  if (dict->lookup("YStep", &obj1)->isNum()) {
+  obj1 = dict->lookup("YStep");
+  if (obj1.isNum()) {
     yStepA = obj1.getNum();
   } else {
     yStepA = 1;
     error(errSyntaxWarning, -1, "Invalid or missing YStep in pattern");
   }
-  obj1.free();
-  if (!dict->lookup("Resources", &resDictA)->isDict()) {
-    resDictA.free();
-    resDictA.initNull();
+  resDictA = dict->lookup("Resources");
+  if (!resDictA.isDict()) {
     error(errSyntaxWarning, -1, "Invalid or missing Resources in pattern");
   }
   matrixA[0] = 1; matrixA[1] = 0;
   matrixA[2] = 0; matrixA[3] = 1;
   matrixA[4] = 0; matrixA[5] = 0;
-  if (dict->lookup("Matrix", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 6) {
+  obj1 = dict->lookup("Matrix");
+  if (obj1.isArray() && obj1.arrayGetLength() == 6) {
     for (i = 0; i < 6; ++i) {
-      if (obj1.arrayGet(i, &obj2)->isNum()) {
+      Object obj2 = obj1.arrayGet(i);
+      if (obj2.isNum()) {
 	matrixA[i] = obj2.getNum();
       }
-      obj2.free();
     }
   }
-  obj1.free();
 
-  pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA,
+  return new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA,
 			     &resDictA, matrixA, patObj);
-  resDictA.free();
-  return pat;
 }
 
 GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA,
@@ -3575,16 +3473,14 @@
   }
   xStep = xStepA;
   yStep = yStepA;
-  resDictA->copy(&resDict);
+  resDict = resDictA->copy();
   for (i = 0; i < 6; ++i) {
     matrix[i] = matrixA[i];
   }
-  contentStreamA->copy(&contentStream);
+  contentStream = contentStreamA->copy();
 }
 
 GfxTilingPattern::~GfxTilingPattern() {
-  resDict.free();
-  contentStream.free();
 }
 
 GfxPattern *GfxTilingPattern::copy() {
@@ -3600,7 +3496,7 @@
   Dict *dict;
   GfxShading *shadingA;
   double matrixA[6];
-  Object obj1, obj2;
+  Object obj1;
   int i;
 
   if (!patObj->isDict()) {
@@ -3608,9 +3504,8 @@
   }
   dict = patObj->getDict();
 
-  dict->lookup("Shading", &obj1);
+  obj1 = dict->lookup("Shading");
   shadingA = GfxShading::parse(res, &obj1, out, state);
-  obj1.free();
   if (!shadingA) {
     return NULL;
   }
@@ -3618,16 +3513,15 @@
   matrixA[0] = 1; matrixA[1] = 0;
   matrixA[2] = 0; matrixA[3] = 1;
   matrixA[4] = 0; matrixA[5] = 0;
-  if (dict->lookup("Matrix", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 6) {
+  obj1 = dict->lookup("Matrix");
+  if (obj1.isArray() && obj1.arrayGetLength() == 6) {
     for (i = 0; i < 6; ++i) {
-      if (obj1.arrayGet(i, &obj2)->isNum()) {
+      Object obj2 = obj1.arrayGet(i);
+      if (obj2.isNum()) {
 	matrixA[i] = obj2.getNum();
       }
-      obj2.free();
     }
   }
-  obj1.free();
 
   return new GfxShadingPattern(shadingA, matrixA);
 }
@@ -3696,13 +3590,12 @@
     return NULL;
   }
 
-  if (!dict->lookup("ShadingType", &obj1)->isInt()) {
+  obj1 = dict->lookup("ShadingType");
+  if (!obj1.isInt()) {
     error(errSyntaxWarning, -1, "Invalid ShadingType in shading dictionary");
-    obj1.free();
     return NULL;
   }
   typeA = obj1.getInt();
-  obj1.free();
 
   switch (typeA) {
   case 1:
@@ -3758,43 +3651,41 @@
 }
 
 GBool GfxShading::init(GfxResources *res, Dict *dict, OutputDev *out, GfxState *state) {
-  Object obj1, obj2;
+  Object obj1;
   int i;
 
-  dict->lookup("ColorSpace", &obj1);
+  obj1 = dict->lookup("ColorSpace");
   if (!(colorSpace = GfxColorSpace::parse(res, &obj1, out, state))) {
     error(errSyntaxWarning, -1, "Bad color space in shading dictionary");
-    obj1.free();
     return gFalse;
   }
-  obj1.free();
 
   for (i = 0; i < gfxColorMaxComps; ++i) {
     background.c[i] = 0;
   }
   hasBackground = gFalse;
-  if (dict->lookup("Background", &obj1)->isArray()) {
+  obj1 = dict->lookup("Background");
+  if (obj1.isArray()) {
     if (obj1.arrayGetLength() == colorSpace->getNComps()) {
       hasBackground = gTrue;
       for (i = 0; i < colorSpace->getNComps(); ++i) {
-	background.c[i] = dblToCol(obj1.arrayGet(i, &obj2)->getNum());
-	obj2.free();
+	Object obj2 = obj1.arrayGet(i);
+	background.c[i] = dblToCol(obj2.getNum());
       }
     } else {
       error(errSyntaxWarning, -1, "Bad Background in shading dictionary");
     }
   }
-  obj1.free();
 
   xMin = yMin = xMax = yMax = 0;
   hasBBox = gFalse;
-  if (dict->lookup("BBox", &obj1)->isArray()) {
+  obj1 = dict->lookup("BBox");
+  if (obj1.isArray()) {
     if (obj1.arrayGetLength() == 4) {
-      Object obj3, obj4, obj5;
-      obj1.arrayGet(0, &obj2);
-      obj1.arrayGet(1, &obj3);
-      obj1.arrayGet(2, &obj4);
-      obj1.arrayGet(3, &obj5);
+      Object obj2 = obj1.arrayGet(0);
+      Object obj3 = obj1.arrayGet(1);
+      Object obj4 = obj1.arrayGet(2);
+      Object obj5 = obj1.arrayGet(3);
       if (obj2.isNum() && obj3.isNum() && obj4.isNum() && obj5.isNum())
       {
         hasBBox = gTrue;
@@ -3805,15 +3696,10 @@
       } else {
         error(errSyntaxWarning, -1, "Bad BBox in shading dictionary (Values not numbers)");
       }
-      obj2.free();
-      obj3.free();
-      obj4.free();
-      obj5.free();
     } else {
       error(errSyntaxWarning, -1, "Bad BBox in shading dictionary");
     }
   }
-  obj1.free();
 
   return gTrue;
 }
@@ -3875,65 +3761,53 @@
   double matrixA[6];
   Function *funcsA[gfxColorMaxComps];
   int nFuncsA;
-  Object obj1, obj2;
+  Object obj1;
   int i;
 
   x0A = y0A = 0;
   x1A = y1A = 1;
-  if (dict->lookup("Domain", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 4) {
-    x0A = obj1.arrayGet(0, &obj2)->getNum();
-    obj2.free();
-    x1A = obj1.arrayGet(1, &obj2)->getNum();
-    obj2.free();
-    y0A = obj1.arrayGet(2, &obj2)->getNum();
-    obj2.free();
-    y1A = obj1.arrayGet(3, &obj2)->getNum();
-    obj2.free();
+  obj1 = dict->lookup("Domain");
+  if (obj1.isArray() && obj1.arrayGetLength() == 4) {
+    Object obj2;
+    x0A = (obj2 = obj1.arrayGet(0), obj2.getNum());
+    x1A = (obj2 = obj1.arrayGet(1), obj2.getNum());
+    y0A = (obj2 = obj1.arrayGet(2), obj2.getNum());
+    y1A = (obj2 = obj1.arrayGet(3), obj2.getNum());
   }
-  obj1.free();
 
   matrixA[0] = 1; matrixA[1] = 0;
   matrixA[2] = 0; matrixA[3] = 1;
   matrixA[4] = 0; matrixA[5] = 0;
-  if (dict->lookup("Matrix", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 6) {
-    matrixA[0] = obj1.arrayGet(0, &obj2)->getNum();
-    obj2.free();
-    matrixA[1] = obj1.arrayGet(1, &obj2)->getNum();
-    obj2.free();
-    matrixA[2] = obj1.arrayGet(2, &obj2)->getNum();
-    obj2.free();
-    matrixA[3] = obj1.arrayGet(3, &obj2)->getNum();
-    obj2.free();
-    matrixA[4] = obj1.arrayGet(4, &obj2)->getNum();
-    obj2.free();
-    matrixA[5] = obj1.arrayGet(5, &obj2)->getNum();
-    obj2.free();
+  obj1 = dict->lookup("Matrix");
+  if (obj1.isArray() && obj1.arrayGetLength() == 6) {
+    Object obj2;
+    matrixA[0] = (obj2 = obj1.arrayGet(0), obj2.getNum());
+    matrixA[1] = (obj2 = obj1.arrayGet(1), obj2.getNum());
+    matrixA[2] = (obj2 = obj1.arrayGet(2), obj2.getNum());
+    matrixA[3] = (obj2 = obj1.arrayGet(3), obj2.getNum());
+    matrixA[4] = (obj2 = obj1.arrayGet(4), obj2.getNum());
+    matrixA[5] = (obj2 = obj1.arrayGet(5), obj2.getNum());
   }
-  obj1.free();
 
-  dict->lookup("Function", &obj1);
+  obj1 = dict->lookup("Function");
   if (obj1.isArray()) {
     nFuncsA = obj1.arrayGetLength();
     if (nFuncsA > gfxColorMaxComps || nFuncsA <= 0) {
       error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary");
-      goto err1;
+      return nullptr;
     }
     for (i = 0; i < nFuncsA; ++i) {
-      obj1.arrayGet(i, &obj2);
+      Object obj2 = obj1.arrayGet(i);
       if (!(funcsA[i] = Function::parse(&obj2))) {
-	goto err2;
+	return nullptr;
       }
-      obj2.free();
     }
   } else {
     nFuncsA = 1;
     if (!(funcsA[0] = Function::parse(&obj1))) {
-      goto err1;
+      return nullptr;
     }
   }
-  obj1.free();
 
   shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA,
 				   funcsA, nFuncsA);
@@ -3942,12 +3816,6 @@
     return NULL;
   }
   return shading;
-
- err2:
-  obj2.free();
- err1:
-  obj1.free();
-  return NULL;
 }
 
 GfxShading *GfxFunctionShading::copy() {
@@ -4204,104 +4072,83 @@
   Function *funcsA[gfxColorMaxComps];
   int nFuncsA;
   GBool extend0A, extend1A;
-  Object obj1, obj2;
+  Object obj1;
   int i;
 
   x0A = y0A = x1A = y1A = 0;
-  if (dict->lookup("Coords", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 4) {
-    Object obj3, obj4, obj5;
-    obj1.arrayGet(0, &obj2);
-    obj1.arrayGet(1, &obj3);
-    obj1.arrayGet(2, &obj4);
-    obj1.arrayGet(3, &obj5);
+  obj1 = dict->lookup("Coords");
+  if (obj1.isArray() && obj1.arrayGetLength() == 4) {
+    Object obj2 = obj1.arrayGet(0);
+    Object obj3 = obj1.arrayGet(1);
+    Object obj4 = obj1.arrayGet(2);
+    Object obj5 = obj1.arrayGet(3);
     if (obj2.isNum() && obj3.isNum() && obj4.isNum() && obj5.isNum()) {
       x0A = obj2.getNum();
       y0A = obj3.getNum();
       x1A = obj4.getNum();
       y1A = obj5.getNum();
     }
-    obj2.free();
-    obj3.free();
-    obj4.free();
-    obj5.free();
   } else {
     error(errSyntaxWarning, -1, "Missing or invalid Coords in shading dictionary");
-    goto err1;
+    return nullptr;
   }
-  obj1.free();
 
   t0A = 0;
   t1A = 1;
-  if (dict->lookup("Domain", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 2) {
-    Object obj3;
-    obj1.arrayGet(0, &obj2);
-    obj1.arrayGet(1, &obj3);
+  obj1 = dict->lookup("Domain");
+  if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+    Object obj2 = obj1.arrayGet(0);
+    Object obj3 = obj1.arrayGet(1);
     if (obj2.isNum() && obj3.isNum()) {
       t0A = obj2.getNum();
       t1A = obj3.getNum();
     }
-    obj2.free();
-    obj3.free();
   }
-  obj1.free();
 
-  dict->lookup("Function", &obj1);
+  obj1 = dict->lookup("Function");
   if (obj1.isArray()) {
     nFuncsA = obj1.arrayGetLength();
     if (nFuncsA > gfxColorMaxComps || nFuncsA == 0) {
       error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary");
-      goto err1;
+      return nullptr;
     }
     for (i = 0; i < nFuncsA; ++i) {
-      obj1.arrayGet(i, &obj2);
+      Object obj2 = obj1.arrayGet(i);
       if (!(funcsA[i] = Function::parse(&obj2))) {
-	obj1.free();
-	obj2.free();
-	goto err1;
+	return nullptr;
       }
-      obj2.free();
     }
   } else {
     nFuncsA = 1;
     if (!(funcsA[0] = Function::parse(&obj1))) {
-      obj1.free();
-      goto err1;
+      return nullptr;
     }
   }
-  obj1.free();
 
   extend0A = extend1A = gFalse;
-  if (dict->lookup("Extend", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 2) {
-    obj1.arrayGet(0, &obj2);
+  obj1 = dict->lookup("Extend");
+  if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+    Object obj2 = obj1.arrayGet(0);
     if (obj2.isBool()) {
       extend0A = obj2.getBool();
     } else {
       error(errSyntaxWarning, -1, "Invalid axial shading extend (0)");
     }
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     if (obj2.isBool()) {
       extend1A = obj2.getBool();
     } else {
       error(errSyntaxWarning, -1, "Invalid axial shading extend (1)");
     }
-    obj2.free();
   }
-  obj1.free();
 
   shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
 				funcsA, nFuncsA, extend0A, extend1A);
   if (!shading->init(res, dict, out, state)) {
     delete shading;
-    return NULL;
+    shading = nullptr;
   }
   return shading;
-
- err1:
-  return NULL;
 }
 
 GfxShading *GfxAxialShading::copy() {
@@ -4412,75 +4259,60 @@
   Function *funcsA[gfxColorMaxComps];
   int nFuncsA;
   GBool extend0A, extend1A;
-  Object obj1, obj2;
+  Object obj1;
   int i;
 
   x0A = y0A = r0A = x1A = y1A = r1A = 0;
-  if (dict->lookup("Coords", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 6) {
-    x0A = obj1.arrayGet(0, &obj2)->getNum();
-    obj2.free();
-    y0A = obj1.arrayGet(1, &obj2)->getNum();
-    obj2.free();
-    r0A = obj1.arrayGet(2, &obj2)->getNum();
-    obj2.free();
-    x1A = obj1.arrayGet(3, &obj2)->getNum();
-    obj2.free();
-    y1A = obj1.arrayGet(4, &obj2)->getNum();
-    obj2.free();
-    r1A = obj1.arrayGet(5, &obj2)->getNum();
-    obj2.free();
+  obj1 = dict->lookup("Coords");
+  if (obj1.isArray() && obj1.arrayGetLength() == 6) {
+    Object obj2;
+    x0A = (obj2 = obj1.arrayGet(0), obj2.getNum());
+    y0A = (obj2 = obj1.arrayGet(1), obj2.getNum());
+    r0A = (obj2 = obj1.arrayGet(2), obj2.getNum());
+    x1A = (obj2 = obj1.arrayGet(3), obj2.getNum());
+    y1A = (obj2 = obj1.arrayGet(4), obj2.getNum());
+    r1A = (obj2 = obj1.arrayGet(5), obj2.getNum());
   } else {
     error(errSyntaxWarning, -1, "Missing or invalid Coords in shading dictionary");
-    goto err1;
+    return nullptr;
   }
-  obj1.free();
 
   t0A = 0;
   t1A = 1;
-  if (dict->lookup("Domain", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 2) {
-    t0A = obj1.arrayGet(0, &obj2)->getNum();
-    obj2.free();
-    t1A = obj1.arrayGet(1, &obj2)->getNum();
-    obj2.free();
+  obj1 = dict->lookup("Domain");
+  if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+    Object obj2;
+    t0A = (obj2 = obj1.arrayGet(0), obj2.getNum());
+    t1A = (obj2 = obj1.arrayGet(1), obj2.getNum());
   }
-  obj1.free();
 
-  dict->lookup("Function", &obj1);
+  obj1 = dict->lookup("Function");
   if (obj1.isArray()) {
     nFuncsA = obj1.arrayGetLength();
     if (nFuncsA > gfxColorMaxComps) {
       error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary");
-      goto err1;
+      return nullptr;
     }
     for (i = 0; i < nFuncsA; ++i) {
-      obj1.arrayGet(i, &obj2);
+      Object obj2 = obj1.arrayGet(i);
       if (!(funcsA[i] = Function::parse(&obj2))) {
-	obj1.free();
-	obj2.free();
-	goto err1;
+	return nullptr;
       }
-      obj2.free();
     }
   } else {
     nFuncsA = 1;
     if (!(funcsA[0] = Function::parse(&obj1))) {
-      obj1.free();
-      goto err1;
+      return nullptr;
     }
   }
-  obj1.free();
 
   extend0A = extend1A = gFalse;
-  if (dict->lookup("Extend", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 2) {
-    extend0A = obj1.arrayGet(0, &obj2)->getBool();
-    obj2.free();
-    extend1A = obj1.arrayGet(1, &obj2)->getBool();
-    obj2.free();
+  obj1 = dict->lookup("Extend");
+  if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+    Object obj2;
+    extend0A = (obj2 = obj1.arrayGet(0), obj2.getBool());
+    extend1A = (obj2 = obj1.arrayGet(1), obj2.getBool());
   }
-  obj1.free();
 
   shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
 				 funcsA, nFuncsA, extend0A, extend1A);
@@ -4489,9 +4321,6 @@
     return NULL;
   }
   return shading;
-
- err1:
-  return NULL;
 }
 
 GfxShading *GfxRadialShading::copy() {
@@ -4943,94 +4772,84 @@
   Guint x, y, flag;
   Guint c[gfxColorMaxComps];
   GfxShadingBitBuf *bitBuf;
-  Object obj1, obj2;
+  Object obj1;
   int i, j, k, state;
 
-  if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
+  obj1 = dict->lookup("BitsPerCoordinate");
+  if (obj1.isInt()) {
     coordBits = obj1.getInt();
   } else {
     error(errSyntaxWarning, -1, "Missing or invalid BitsPerCoordinate in shading dictionary");
-    goto err2;
+    return nullptr;
   }
-  obj1.free();
-  if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
+  obj1 = dict->lookup("BitsPerComponent");
+  if (obj1.isInt()) {
     compBits = obj1.getInt();
   } else {
     error(errSyntaxWarning, -1, "Missing or invalid BitsPerComponent in shading dictionary");
-    goto err2;
+    return nullptr;
   }
-  obj1.free();
   flagBits = vertsPerRow = 0; // make gcc happy
   if (typeA == 4) {
-    if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
+    obj1 = dict->lookup("BitsPerFlag");
+  if (obj1.isInt()) {
       flagBits = obj1.getInt();
     } else {
       error(errSyntaxWarning, -1, "Missing or invalid BitsPerFlag in shading dictionary");
-      goto err2;
+      return nullptr;
     }
-    obj1.free();
   } else {
-    if (dict->lookup("VerticesPerRow", &obj1)->isInt()) {
+    obj1 = dict->lookup("VerticesPerRow");
+  if (obj1.isInt()) {
       vertsPerRow = obj1.getInt();
     } else {
       error(errSyntaxWarning, -1, "Missing or invalid VerticesPerRow in shading dictionary");
-      goto err2;
+      return nullptr;
     }
-    obj1.free();
   }
-  if (dict->lookup("Decode", &obj1)->isArray() &&
-      obj1.arrayGetLength() >= 6) {
-    xMin = obj1.arrayGet(0, &obj2)->getNum();
-    obj2.free();
-    xMax = obj1.arrayGet(1, &obj2)->getNum();
-    obj2.free();
+  obj1 = dict->lookup("Decode");
+  if (obj1.isArray() && obj1.arrayGetLength() >= 6) {
+    Object obj2;
+    xMin = (obj2 = obj1.arrayGet(0), obj2.getNum());
+    xMax = (obj2 = obj1.arrayGet(1), obj2.getNum());
     xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
-    yMin = obj1.arrayGet(2, &obj2)->getNum();
-    obj2.free();
-    yMax = obj1.arrayGet(3, &obj2)->getNum();
-    obj2.free();
+    yMin = (obj2 = obj1.arrayGet(2), obj2.getNum());
+    yMax = (obj2 = obj1.arrayGet(3), obj2.getNum());
     yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
     for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
-      cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum();
-      obj2.free();
-      cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum();
-      obj2.free();
+      cMin[i] = (obj2 = obj1.arrayGet(4 + 2*i), obj2.getNum());
+      cMax[i] = (obj2 = obj1.arrayGet(5 + 2*i), obj2.getNum());
       cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
     }
     nComps = i;
   } else {
     error(errSyntaxWarning, -1, "Missing or invalid Decode array in shading dictionary");
-    goto err2;
+    return nullptr;
   }
-  obj1.free();
 
-  if (!dict->lookup("Function", &obj1)->isNull()) {
+  obj1 = dict->lookup("Function");
+  if (!obj1.isNull()) {
     if (obj1.isArray()) {
       nFuncsA = obj1.arrayGetLength();
       if (nFuncsA > gfxColorMaxComps) {
 	error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary");
-	goto err1;
+	return nullptr;
       }
       for (i = 0; i < nFuncsA; ++i) {
-	obj1.arrayGet(i, &obj2);
+	Object obj2 = obj1.arrayGet(i);
 	if (!(funcsA[i] = Function::parse(&obj2))) {
-	  obj1.free();
-	  obj2.free();
-	  goto err1;
+	  return nullptr;
 	}
-	obj2.free();
       }
     } else {
       nFuncsA = 1;
       if (!(funcsA[0] = Function::parse(&obj1))) {
-	obj1.free();
-	goto err1;
+	return nullptr;
       }
     }
   } else {
     nFuncsA = 0;
   }
-  obj1.free();
 
   nVerticesA = nTrianglesA = 0;
   verticesA = NULL;
@@ -5129,11 +4948,6 @@
     return NULL;
   }
   return shading;
-
- err2:
-  obj1.free();
- err1:
-  return NULL;
 }
 
 GfxShading *GfxGouraudTriangleShading::copy() {
@@ -5294,89 +5108,79 @@
   double c[4][gfxColorMaxComps];
   Guint ci;
   GfxShadingBitBuf *bitBuf;
-  Object obj1, obj2;
+  Object obj1;
   int i, j;
 
-  if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
+  obj1 = dict->lookup("BitsPerCoordinate");
+  if (obj1.isInt()) {
     coordBits = obj1.getInt();
   } else {
     error(errSyntaxWarning, -1, "Missing or invalid BitsPerCoordinate in shading dictionary");
-    goto err2;
+    return nullptr;
   }
-  obj1.free();
-  if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
+  obj1 = dict->lookup("BitsPerComponent");
+  if (obj1.isInt()) {
     compBits = obj1.getInt();
   } else {
     error(errSyntaxWarning, -1, "Missing or invalid BitsPerComponent in shading dictionary");
-    goto err2;
+    return nullptr;
   }
-  obj1.free();
-  if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
+  obj1 = dict->lookup("BitsPerFlag");
+  if (obj1.isInt()) {
     flagBits = obj1.getInt();
   } else {
     error(errSyntaxWarning, -1, "Missing or invalid BitsPerFlag in shading dictionary");
-    goto err2;
+    return nullptr;
   }
-  obj1.free();
-  if (dict->lookup("Decode", &obj1)->isArray() &&
-      obj1.arrayGetLength() >= 6) {
+  obj1 = dict->lookup("Decode");
+  if (obj1.isArray() && obj1.arrayGetLength() >= 6) {
     bool decodeOk = true;
-    xMin = obj1.arrayGet(0, &obj2)->getNum(&decodeOk);
-    obj2.free();
-    xMax = obj1.arrayGet(1, &obj2)->getNum(&decodeOk);
-    obj2.free();
+    Object obj2;
+    xMin = (obj2 = obj1.arrayGet(0), obj2.getNum(&decodeOk));
+    xMax = (obj2 = obj1.arrayGet(1), obj2.getNum(&decodeOk));
     xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
-    yMin = obj1.arrayGet(2, &obj2)->getNum(&decodeOk);
-    obj2.free();
-    yMax = obj1.arrayGet(3, &obj2)->getNum(&decodeOk);
-    obj2.free();
+    yMin = (obj2 = obj1.arrayGet(2), obj2.getNum(&decodeOk));
+    yMax = (obj2 = obj1.arrayGet(3), obj2.getNum(&decodeOk));
     yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
     for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
-      cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum(&decodeOk);
-      obj2.free();
-      cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum(&decodeOk);
-      obj2.free();
+      cMin[i] = (obj2 = obj1.arrayGet(4 + 2*i), obj2.getNum(&decodeOk));
+      cMax[i] = (obj2 = obj1.arrayGet(5 + 2*i), obj2.getNum(&decodeOk));
       cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
     }
     nComps = i;
 
     if (!decodeOk) {
       error(errSyntaxWarning, -1, "Missing or invalid Decode array in shading dictionary");
-      goto err2;
+      return nullptr;
     }
   } else {
     error(errSyntaxWarning, -1, "Missing or invalid Decode array in shading dictionary");
-    goto err2;
+    return nullptr;
   }
-  obj1.free();
 
-  if (!dict->lookup("Function", &obj1)->isNull()) {
+  obj1 = dict->lookup("Function");
+  if (!obj1.isNull()) {
     if (obj1.isArray()) {
       nFuncsA = obj1.arrayGetLength();
       if (nFuncsA > gfxColorMaxComps) {
 	error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary");
-	goto err1;
+	return nullptr;
       }
       for (i = 0; i < nFuncsA; ++i) {
-	obj1.arrayGet(i, &obj2);
+	Object obj2 = obj1.arrayGet(i);
 	if (!(funcsA[i] = Function::parse(&obj2))) {
-	  obj1.free();
-	  obj2.free();
-	  goto err1;
+	  return nullptr;
 	}
-	obj2.free();
       }
     } else {
       nFuncsA = 1;
       if (!(funcsA[0] = Function::parse(&obj1))) {
-	obj1.free();
-	goto err1;
+	return nullptr;
       }
     }
   } else {
     nFuncsA = 0;
   }
-  obj1.free();
 
   nPatchesA = 0;
   patchesA = NULL;
@@ -5477,7 +5281,7 @@
 	break;
       case 1:
 	if (nPatchesA == 0) {
-	  goto err1;
+	  return nullptr;
 	}
 	p->x[0][0] = patchesA[nPatchesA-1].x[0][3];
 	p->y[0][0] = patchesA[nPatchesA-1].y[0][3];
@@ -5512,7 +5316,7 @@
 	break;
       case 2:
 	if (nPatchesA == 0) {
-	  goto err1;
+	  return nullptr;
 	}
 	p->x[0][0] = patchesA[nPatchesA-1].x[3][3];
 	p->y[0][0] = patchesA[nPatchesA-1].y[3][3];
@@ -5547,7 +5351,7 @@
 	break;
       case 3:
 	if (nPatchesA == 0) {
-	  goto err1;
+	  return nullptr;
 	}
 	p->x[0][0] = patchesA[nPatchesA-1].x[3][0];
 	p->y[0][0] = patchesA[nPatchesA-1].y[3][0];
@@ -5625,7 +5429,7 @@
 	break;
       case 1:
 	if (nPatchesA == 0) {
-	  goto err1;
+	  return nullptr;
 	}
 	p->x[0][0] = patchesA[nPatchesA-1].x[0][3];
 	p->y[0][0] = patchesA[nPatchesA-1].y[0][3];
@@ -5668,7 +5472,7 @@
 	break;
       case 2:
 	if (nPatchesA == 0) {
-	  goto err1;
+	  return nullptr;
 	}
 	p->x[0][0] = patchesA[nPatchesA-1].x[3][3];
 	p->y[0][0] = patchesA[nPatchesA-1].y[3][3];
@@ -5711,7 +5515,7 @@
 	break;
       case 3:
 	if (nPatchesA == 0) {
-	  goto err1;
+	  return nullptr;
 	}
 	p->x[0][0] = patchesA[nPatchesA-1].x[3][0];
 	p->y[0][0] = patchesA[nPatchesA-1].y[3][0];
@@ -5809,14 +5613,9 @@
 				    funcsA, nFuncsA);
   if (!shading->init(res, dict, out, state)) {
     delete shading;
-    return NULL;
+    return nullptr;
   }
   return shading;
-
- err2:
-  obj1.free();
- err1:
-  return NULL;
 }
 
 void GfxPatchMeshShading::getParameterizedColor(double t, GfxColor *color) {
@@ -5845,7 +5644,6 @@
   int maxPixel, indexHigh;
   Guchar *indexedLookup;
   Function *sepFunc;
-  Object obj;
   double x[gfxColorMaxComps];
   double y[gfxColorMaxComps];
   int i, j, k;
@@ -5887,18 +5685,16 @@
       nComps = colorSpace->getNComps();
     }
     for (i = 0; i < nComps; ++i) {
-      decode->arrayGet(2*i, &obj);
+      Object obj = decode->arrayGet(2*i);
       if (!obj.isNum()) {
-	goto err2;
+	goto err1;
       }
       decodeLow[i] = obj.getNum();
-      obj.free();
-      decode->arrayGet(2*i+1, &obj);
+      obj = decode->arrayGet(2*i+1);
       if (!obj.isNum()) {
-	goto err2;
+	goto err1;
       }
       decodeRange[i] = obj.getNum() - decodeLow[i];
-      obj.free();
     }
   } else {
     goto err1;
@@ -6003,8 +5799,6 @@
 
   return;
 
- err2:
-  obj.free();
  err1:
   ok = gFalse;
 }
@@ -7328,7 +7122,6 @@
 }
 
 GBool GfxState::parseBlendMode(Object *obj, GfxBlendMode *mode) {
-  Object obj2;
   int i, j;
 
   if (obj->isName()) {
@@ -7341,19 +7134,16 @@
     return gFalse;
   } else if (obj->isArray()) {
     for (i = 0; i < obj->arrayGetLength(); ++i) {
-      obj->arrayGet(i, &obj2);
+      Object obj2 = obj->arrayGet(i);
       if (!obj2.isName()) {
-	obj2.free();
 	return gFalse;
       }
       for (j = 0; j < nGfxBlendModeNames; ++j) {
 	if (!strcmp(obj2.getName(), gfxBlendModeNames[j].name)) {
-	  obj2.free();
 	  *mode = gfxBlendModeNames[j].mode;
 	  return gTrue;
 	}
       }
-      obj2.free();
     }
     *mode = gfxBlendNormal;
     return gTrue;
diff --git a/poppler/Hints.cc b/poppler/Hints.cc
index 7f11304..270b6e4 100644
--- a/poppler/Hints.cc
+++ b/poppler/Hints.cc
@@ -5,7 +5,7 @@
 // This file is licensed under the GPLv2 or later
 //
 // Copyright 2010, 2012 Hib Eris <hib@hiberis.nl>
-// Copyright 2010, 2011, 2013, 2014, 2016 Albert Astals Cid <aacid@kde.org>
+// Copyright 2010, 2011, 2013, 2014, 2016, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright 2010, 2013 Pino Toscano <pino@kde.org>
 // Copyright 2013 Adrian Johnson <ajohnson@redneon.com>
 // Copyright 2014 Fabio D'Urso <fabiodurso@hotmail.it>
@@ -181,42 +181,38 @@
   hintsLength2 = linearization->getHintsLength2();
 
   Parser *parser;
-  Object obj;
 
   int bufLength = hintsLength + hintsLength2;
 
   std::vector<char> buf(bufLength);
   char *p = &buf[0];
 
-  obj.initNull();
-  Stream *s = str->makeSubStream(hintsOffset, gFalse, hintsLength, &obj);
+  Stream *s = str->makeSubStream(hintsOffset, gFalse, hintsLength, Object(objNull));
   s->reset();
   for (Guint i=0; i < hintsLength; i++) { *p++ = s->getChar(); }
   delete s;
 
   if (hintsOffset2 && hintsLength2) {
-    obj.initNull();
-    s = str->makeSubStream(hintsOffset2, gFalse, hintsLength2, &obj);
+    s = str->makeSubStream(hintsOffset2, gFalse, hintsLength2, Object(objNull));
     s->reset();
     for (Guint i=0; i < hintsLength2; i++) { *p++ = s->getChar(); }
     delete s;
   }
 
-  obj.initNull();
-  MemStream *memStream = new MemStream (&buf[0], 0, bufLength, &obj);
+  MemStream *memStream = new MemStream (&buf[0], 0, bufLength, Object(objNull));
 
-  obj.initNull();
   parser = new Parser(xref, new Lexer(xref, memStream), gTrue);
 
   int num, gen;
-  if (parser->getObj(&obj)->isInt() &&
-     (num = obj.getInt(), obj.free(), parser->getObj(&obj)->isInt()) &&
-     (gen = obj.getInt(), obj.free(), parser->getObj(&obj)->isCmd("obj")) &&
-     (obj.free(), parser->getObj(&obj, gFalse,
+  Object obj;
+  if ((obj = parser->getObj(), obj.isInt()) &&
+     (num = obj.getInt(), obj = parser->getObj(), obj.isInt()) &&
+     (gen = obj.getInt(), obj = parser->getObj(), obj.isCmd("obj")) &&
+     (obj = parser->getObj(gFalse,
          secHdlr ? secHdlr->getFileKey() : (Guchar *)NULL,
          secHdlr ? secHdlr->getEncAlgorithm() : cryptRC4,
          secHdlr ? secHdlr->getFileKeyLength() : 0,
-         num, gen, 0, gTrue)->isStream())) {
+         num, gen, 0, gTrue), obj.isStream())) {
     Stream *hintsStream = obj.getStream();
     Dict *hintsDict = obj.streamGetDict();
 
@@ -238,7 +234,6 @@
   } else {
     error(errSyntaxWarning, -1, "Failed parsing hints table object");
   }
-  obj.free();
 
   delete parser;
 }
diff --git a/poppler/JBIG2Stream.cc b/poppler/JBIG2Stream.cc
index d89108c..50c6eee 100644
--- a/poppler/JBIG2Stream.cc
+++ b/poppler/JBIG2Stream.cc
@@ -1201,7 +1201,7 @@
   mmrDecoder = new JBIG2MMRDecoder();
 
   if (globalsStreamA->isStream()) {
-    globalsStreamA->copy(&globalsStream);
+    globalsStream = globalsStreamA->copy();
     if (globalsStreamRefA->isRef())
       globalsStreamRef = globalsStreamRefA->getRef();
   }
@@ -1213,7 +1213,6 @@
 
 JBIG2Stream::~JBIG2Stream() {
   close();
-  globalsStream.free();
   delete arithDecoder;
   delete genericRegionStats;
   delete refinementRegionStats;
diff --git a/poppler/JPEG2000Stream.cc b/poppler/JPEG2000Stream.cc
index 7daa23d..2b6af90 100644
--- a/poppler/JPEG2000Stream.cc
+++ b/poppler/JPEG2000Stream.cc
@@ -4,7 +4,7 @@
 //
 // A JPX stream decoder using OpenJPEG
 //
-// Copyright 2008-2010, 2012 Albert Astals Cid <aacid@kde.org>
+// Copyright 2008-2010, 2012, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright 2011 Daniel Glöckner <daniel-gl@gmx.net>
 // Copyright 2014, 2016 Thomas Freitag <Thomas.Freitag@alfa.de>
 // Copyright 2013, 2014 Adrian Johnson <ajohnson@redneon.com>
@@ -363,25 +363,22 @@
 void JPXStream::init()
 {
   Object oLen, cspace, smaskInData;
-  if (getDict()) getDict()->lookup("Length", &oLen);
-  if (getDict()) getDict()->lookup("ColorSpace", &cspace);
-  if (getDict()) getDict()->lookup("SMaskInData", &smaskInData);
+  if (getDict()) {
+    oLen = getDict()->lookup("Length");
+    cspace = getDict()->lookup("ColorSpace");
+    smaskInData = getDict()->lookup("SMaskInData");
+  }
 
   int bufSize = BUFFER_INITIAL_SIZE;
   if (oLen.isInt()) bufSize = oLen.getInt();
-  oLen.free();
 
   if (cspace.isArray() && cspace.arrayGetLength() > 0) {
-    Object cstype;
-    cspace.arrayGet(0, &cstype);
+    Object cstype = cspace.arrayGet(0);
     if (cstype.isName("Indexed")) priv->indexed = gTrue;
-    cstype.free();
   }
-  cspace.free();
 
   priv->smaskInData = 0;
   if (smaskInData.isInt()) priv->smaskInData = smaskInData.getInt();
-  smaskInData.free();
 
   int length = 0;
   unsigned char *buf = str->toUnsignedChars(&length, bufSize);
@@ -504,6 +501,7 @@
     return;
 
 error:
+  opj_stream_destroy(stream);
   opj_destroy_codec(decoder);
   if (format == OPJ_CODEC_JP2) {
     error(errSyntaxWarning, -1, "Did no succeed opening JPX Stream as JP2, trying as J2K.");
diff --git a/poppler/Lexer.cc b/poppler/Lexer.cc
index 952967a..d2329b5 100644
--- a/poppler/Lexer.cc
+++ b/poppler/Lexer.cc
@@ -13,7 +13,7 @@
 // All changes made under the Poppler project to this file are licensed
 // under GPL version 2 or later
 //
-// Copyright (C) 2006-2010, 2012-2014 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006-2010, 2012-2014, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2006 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
 // Copyright (C) 2010 Carlos Garcia Campos <carlosgc@gnome.org>
 // Copyright (C) 2012, 2013 Adrian Johnson <ajohnson@redneon.com>
@@ -70,36 +70,33 @@
 //------------------------------------------------------------------------
 
 Lexer::Lexer(XRef *xrefA, Stream *str) {
-  Object obj;
-
   lookCharLastValueCached = LOOK_VALUE_NOT_CACHED;
   xref = xrefA;
 
-  curStr.initStream(str);
+  curStr = Object(str);
   streams = new Array(xref);
-  streams->add(curStr.copy(&obj));
+  streams->add(curStr.copy());
   strPtr = 0;
   freeArray = gTrue;
   curStr.streamReset();
 }
 
 Lexer::Lexer(XRef *xrefA, Object *obj) {
-  Object obj2;
-
   lookCharLastValueCached = LOOK_VALUE_NOT_CACHED;
   xref = xrefA;
 
   if (obj->isStream()) {
+    Object obj2;
     streams = new Array(xref);
     freeArray = gTrue;
-    streams->add(obj->copy(&obj2));
+    streams->add(obj->copy());
   } else {
     streams = obj->getArray();
     freeArray = gFalse;
   }
   strPtr = 0;
   if (streams->getLength() > 0) {
-    streams->get(strPtr, &curStr);
+    curStr = streams->get(strPtr);
     curStr.streamReset();
   }
 }
@@ -107,7 +104,6 @@
 Lexer::~Lexer() {
   if (!curStr.isNone()) {
     curStr.streamClose();
-    curStr.free();
   }
   if (freeArray) {
     delete streams;
@@ -129,10 +125,10 @@
       return EOF;
     } else {
       curStr.streamClose();
-      curStr.free();
+      curStr = Object();
       ++strPtr;
       if (strPtr < streams->getLength()) {
-        streams->get(strPtr, &curStr);
+        curStr = streams->get(strPtr);
         curStr.streamReset();
       }
     }
@@ -154,7 +150,7 @@
   }
 }
 
-Object *Lexer::getObj(Object *obj, int objNum) {
+Object Lexer::getObj(int objNum) {
   char *p;
   int c, c2;
   GBool comment, neg, done, overflownInteger, overflownLongLong;
@@ -169,7 +165,7 @@
   comment = gFalse;
   while (1) {
     if ((c = getChar()) == EOF) {
-      return obj->initEOF();
+      return Object(objEOF);
     }
     if (comment) {
       if (c == '\r' || c == '\n')
@@ -236,16 +232,16 @@
     }
     if (unlikely(overflownInteger)) {
       if (overflownLongLong) {
-        obj->initReal(xf);
+        return Object(xf);
       } else {
         if (unlikely(xll == INT_MIN)) {
-          obj->initInt(INT_MIN);
+          return Object(static_cast<int>(INT_MIN));
         } else {
-          obj->initInt64(xll);
+          return Object(xll);
         }
       }
     } else {
-      obj->initInt(xi);
+      return Object(xi);
     }
     break;
   doReal:
@@ -274,7 +270,7 @@
     if (neg) {
       xf = -xf;
     }
-    obj->initReal(xf);
+    return Object(xf);
     break;
 
   // string
@@ -401,9 +397,9 @@
         s = new GooString(tokBuf, n);
       else
         s->append(tokBuf, n);
-      obj->initString(s);
+      return Object(s);
     } else {
-      obj->initEOF();
+      return Object(objEOF);
     }
     break;
 
@@ -455,10 +451,11 @@
     }
     if (n < tokBufSize) {
       *p = '\0';
-      obj->initName(tokBuf);
+      return Object(objName, tokBuf);
     } else {
-      obj->initName(s->getCString());
+      Object obj(objName, s->getCString());
       delete s;
+      return obj;
     }
     break;
 
@@ -467,7 +464,7 @@
   case ']':
     tokBuf[0] = c;
     tokBuf[1] = '\0';
-    obj->initCmd(tokBuf);
+    return Object(objCmd, tokBuf);
     break;
 
   // hex string or dict punctuation
@@ -479,7 +476,7 @@
       getChar();
       tokBuf[0] = tokBuf[1] = '<';
       tokBuf[2] = '\0';
-      obj->initCmd(tokBuf);
+      return Object(objCmd, tokBuf);
 
     // hex string
     } else {
@@ -526,7 +523,7 @@
 	s->append(tokBuf, n);
       if (m == 1)
 	s->append((char)(c2 << 4));
-      obj->initString(s);
+      return Object(s);
     }
     break;
 
@@ -537,10 +534,10 @@
       getChar();
       tokBuf[0] = tokBuf[1] = '>';
       tokBuf[2] = '\0';
-      obj->initCmd(tokBuf);
+      return Object(objCmd, tokBuf);
     } else {
       error(errSyntaxError, getPos(), "Illegal character '>'");
-      obj->initError();
+      return Object(objError);
     }
     break;
 
@@ -549,7 +546,7 @@
   case '{':
   case '}':
     error(errSyntaxError, getPos(), "Illegal character '{0:c}'", c);
-    obj->initError();
+    return Object(objError);
     break;
 
   // command
@@ -567,21 +564,21 @@
     }
     *p = '\0';
     if (tokBuf[0] == 't' && !strcmp(tokBuf, "true")) {
-      obj->initBool(gTrue);
+      return Object(gTrue);
     } else if (tokBuf[0] == 'f' && !strcmp(tokBuf, "false")) {
-      obj->initBool(gFalse);
+      return Object(gFalse);
     } else if (tokBuf[0] == 'n' && !strcmp(tokBuf, "null")) {
-      obj->initNull();
+      return Object(objNull);
     } else {
-      obj->initCmd(tokBuf);
+      return Object(objCmd, tokBuf);
     }
     break;
   }
 
-  return obj;
+  return Object();
 }
 
-Object *Lexer::getObj(Object *obj, const char *cmdA, int objNum) {
+Object Lexer::getObj(const char *cmdA, int objNum) {
   char *p;
   int c;
   GBool comment;
@@ -594,7 +591,7 @@
   while (strcmp(cmdA, cmd1) && (objNum < 0 || (xref && xref->getNumEntry(getPos()) == objNum))) {
     while (1) {
       if ((c = getChar()) == EOF) {
-        return obj->initEOF();
+        return Object(objEOF);
       }
       if (comment) {
         if (c == '\r' || c == '\n') {
@@ -618,9 +615,8 @@
     }
     *p = '\0';
   }
-  obj->initCmd(tokBuf);
-  
-  return obj;
+
+  return Object(objCmd, tokBuf);
 }
 
 void Lexer::skipToNextLine() {
diff --git a/poppler/Lexer.h b/poppler/Lexer.h
index 02b6cdc..ac3334c 100644
--- a/poppler/Lexer.h
+++ b/poppler/Lexer.h
@@ -13,7 +13,7 @@
 // All changes made under the Poppler project to this file are licensed
 // under GPL version 2 or later
 //
-// Copyright (C) 2006, 2007, 2010, 2013 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006, 2007, 2010, 2013, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2006 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
 // Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
 // Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
@@ -56,8 +56,9 @@
   ~Lexer();
 
   // Get the next object from the input stream.
-  Object *getObj(Object *obj, int objNum = -1);
-  Object *getObj(Object *obj, const char *cmdA, int objNum);
+  Object getObj(int objNum = -1);
+  Object getObj(const char *cmdA, int objNum);
+  template<typename T> Object getObj(T) = delete;
 
   // Skip to the beginning of the next line in the input stream.
   void skipToNextLine();
diff --git a/poppler/Linearization.cc b/poppler/Linearization.cc
index be041f9..49008a3 100644
--- a/poppler/Linearization.cc
+++ b/poppler/Linearization.cc
@@ -6,6 +6,7 @@
 //
 // Copyright 2010, 2012 Hib Eris <hib@hiberis.nl>
 // Copyright 2015 Jason Crain <jason@aquaticape.us>
+// Copyright 2017 Albert Astals Cid <aacid@kde.org>
 //
 //========================================================================
 
@@ -20,36 +21,26 @@
 Linearization::Linearization (BaseStream *str)
 {
   Parser *parser;
-  Object obj1, obj2, obj3, obj5;
-
-  linDict.initNull();
 
   str->reset();
-  obj1.initNull();
   parser = new Parser(NULL,
-      new Lexer(NULL, str->makeSubStream(str->getStart(), gFalse, 0, &obj1)),
+      new Lexer(NULL, str->makeSubStream(str->getStart(), gFalse, 0, Object(objNull))),
       gFalse);
-  parser->getObj(&obj1);
-  parser->getObj(&obj2);
-  parser->getObj(&obj3);
-  parser->getObj(&linDict);
+  Object obj1 = parser->getObj();
+  Object obj2 = parser->getObj();
+  Object obj3 = parser->getObj();
+  linDict = parser->getObj();
   if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") && linDict.isDict()) {
-    linDict.dictLookup("Linearized", &obj5);
+    Object obj5 = linDict.dictLookup("Linearized");
     if (!(obj5.isNum() && obj5.getNum() > 0)) {
-       linDict.free();
-       linDict.initNull();
+       linDict.setToNull();
     }
-    obj5.free();
   }
-  obj3.free();
-  obj2.free();
-  obj1.free();
   delete parser;
 }
 
 Linearization:: ~Linearization()
 {
-  linDict.free();
 }
 
 Guint Linearization::getLength()
@@ -72,17 +63,15 @@
 
   Object obj1, obj2;
   if (linDict.isDict() &&
-      linDict.dictLookup("H", &obj1)->isArray() &&
+      (obj1 = linDict.dictLookup("H"), obj1.isArray()) &&
       obj1.arrayGetLength()>=2 &&
-      obj1.arrayGet(0, &obj2)->isInt() &&
+      (obj2 = obj1.arrayGet(0), obj2.isInt()) &&
       obj2.getInt() > 0) {
     hintsOffset = obj2.getInt();
   } else {
     error(errSyntaxWarning, -1, "Hints table offset in linearization table is invalid");
     hintsOffset = 0;
   }
-  obj2.free();
-  obj1.free();
 
   return hintsOffset;
 }
@@ -93,17 +82,15 @@
 
   Object obj1, obj2;
   if (linDict.isDict() &&
-      linDict.dictLookup("H", &obj1)->isArray() &&
+      (obj1 = linDict.dictLookup("H"), obj1.isArray()) &&
       obj1.arrayGetLength()>=2 &&
-      obj1.arrayGet(1, &obj2)->isInt() &&
+      (obj2 = obj1.arrayGet(1), obj2.isInt()) &&
       obj2.getInt() > 0) {
     hintsLength = obj2.getInt();
   } else {
     error(errSyntaxWarning, -1, "Hints table length in linearization table is invalid");
     hintsLength = 0;
   }
-  obj2.free();
-  obj1.free();
 
   return hintsLength;
 }
@@ -112,20 +99,18 @@
 {
   int hintsOffset2 = 0; // default to 0
 
-  Object obj1, obj2;
+  Object obj1;
   if (linDict.isDict() &&
-      linDict.dictLookup("H", &obj1)->isArray() &&
+      (obj1 = linDict.dictLookup("H"), obj1.isArray()) &&
       obj1.arrayGetLength()>=4) {
-    if (obj1.arrayGet(2, &obj2)->isInt() &&
-        obj2.getInt() > 0) {
+    Object obj2 = obj1.arrayGet(2);
+    if (obj2.isInt() && obj2.getInt() > 0) {
       hintsOffset2 = obj2.getInt();
     } else {
       error(errSyntaxWarning, -1, "Second hints table offset in linearization table is invalid");
       hintsOffset2 = 0;
     }
   }
-  obj2.free();
-  obj1.free();
 
   return hintsOffset2;
 }
@@ -134,20 +119,18 @@
 {
   int hintsLength2 = 0; // default to 0
 
-  Object obj1, obj2;
+  Object obj1;
   if (linDict.isDict() &&
-      linDict.dictLookup("H", &obj1)->isArray() &&
+      (obj1 = linDict.dictLookup("H"), obj1.isArray()) &&
       obj1.arrayGetLength()>=4) {
-    if (obj1.arrayGet(3, &obj2)->isInt() &&
-        obj2.getInt() > 0) {
+    Object obj2 = obj1.arrayGet(3);
+    if (obj2.isInt() && obj2.getInt() > 0) {
       hintsLength2 = obj2.getInt();
     } else {
       error(errSyntaxWarning, -1, "Second hints table length in linearization table is invalid");
       hintsLength2 = 0;
     }
   }
-  obj2.free();
-  obj1.free();
 
   return hintsLength2;
 }
diff --git a/poppler/Link.cc b/poppler/Link.cc
index d4680db..d7bbc33 100644
--- a/poppler/Link.cc
+++ b/poppler/Link.cc
@@ -16,7 +16,7 @@
 // Copyright (C) 2006, 2008 Pino Toscano <pino@kde.org>
 // Copyright (C) 2007, 2010, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
 // Copyright (C) 2008 Hugo Mercier <hmercier31@gmail.com>
-// Copyright (C) 2008-2010, 2012-2014, 2016 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2008-2010, 2012-2014, 2016, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
 // Copyright (C) 2009 Ilya Gorenbein <igorenbein@finjan.com>
 // Copyright (C) 2012 Tobias Koening <tobias.koenig@kdab.com>
@@ -64,7 +64,6 @@
 
 LinkAction *LinkAction::parseAction(Object *obj, GooString *baseURI) {
   LinkAction *action;
-  Object obj2, obj3, obj4;
 
   if (!obj->isDict()) {
       error(errSyntaxWarning, -1, "parseAction: Bad annotation action for URI '{0:s}'",
@@ -72,21 +71,18 @@
       return NULL;
   }
 
-  obj->dictLookup("S", &obj2);
+  Object obj2 = obj->dictLookup("S");
 
   // GoTo action
   if (obj2.isName("GoTo")) {
-    obj->dictLookup("D", &obj3);
+    Object obj3 = obj->dictLookup("D");
     action = new LinkGoTo(&obj3);
-    obj3.free();
 
   // GoToR action
   } else if (obj2.isName("GoToR")) {
-    obj->dictLookup("F", &obj3);
-    obj->dictLookup("D", &obj4);
+    Object obj3 = obj->dictLookup("F");
+    Object obj4 = obj->dictLookup("D");
     action = new LinkGoToR(&obj3, &obj4);
-    obj3.free();
-    obj4.free();
 
   // Launch action
   } else if (obj2.isName("Launch")) {
@@ -94,15 +90,13 @@
 
   // URI action
   } else if (obj2.isName("URI")) {
-    obj->dictLookup("URI", &obj3);
+    Object obj3 = obj->dictLookup("URI");
     action = new LinkURI(&obj3, baseURI);
-    obj3.free();
 
   // Named action
   } else if (obj2.isName("Named")) {
-    obj->dictLookup("N", &obj3);
+    Object obj3 = obj->dictLookup("N");
     action = new LinkNamed(&obj3);
-    obj3.free();
 
   // Movie action
   } else if (obj2.isName("Movie")) {
@@ -118,9 +112,8 @@
 
   // JavaScript action
   } else if (obj2.isName("JavaScript")) {
-    obj->dictLookup("JS", &obj3);
+    Object obj3 = obj->dictLookup("JS");
     action = new LinkJavaScript(&obj3);
-    obj3.free();
 
   // Set-OCG-State action
   } else if (obj2.isName("SetOCGState")) {
@@ -137,8 +130,6 @@
     action = NULL;
   }
 
-  obj2.free();
-
   if (action && !action->isOk()) {
     delete action;
     return NULL;
@@ -151,8 +142,6 @@
 //------------------------------------------------------------------------
 
 LinkDest::LinkDest(Array *a) {
-  Object obj1, obj2;
-
   // initialize fields
   left = bottom = right = top = zoom = 0;
   changeLeft = changeTop = changeZoom = gFalse;
@@ -163,7 +152,7 @@
     error(errSyntaxWarning, -1, "Annotation destination array is too short");
     return;
   }
-  a->getNF(0, &obj1);
+  Object obj1 = a->getNF(0);
   if (obj1.isInt()) {
     pageNum = obj1.getInt() + 1;
     pageIsRef = gFalse;
@@ -173,12 +162,11 @@
     pageIsRef = gTrue;
   } else {
     error(errSyntaxWarning, -1, "Bad annotation destination");
-    goto err2;
+    return;
   }
-  obj1.free();
 
   // get destination type
-  a->get(1, &obj1);
+  obj1 = a->get(1);
 
   // XYZ link
   if (obj1.isName("XYZ")) {
@@ -186,7 +174,7 @@
     if (a->getLength() < 3) {
       changeLeft = gFalse;
     } else {
-      a->get(2, &obj2);
+      Object obj2 = a->get(2);
       if (obj2.isNull()) {
 	changeLeft = gFalse;
       } else if (obj2.isNum()) {
@@ -194,14 +182,13 @@
 	left = obj2.getNum();
       } else {
 	error(errSyntaxWarning, -1, "Bad annotation destination position");
-	goto err1;
+	return;
       }
-      obj2.free();
     }
     if (a->getLength() < 4) {
       changeTop = gFalse;
     } else {
-      a->get(3, &obj2);
+      Object obj2 = a->get(3);
       if (obj2.isNull()) {
 	changeTop = gFalse;
       } else if (obj2.isNum()) {
@@ -209,14 +196,13 @@
 	top = obj2.getNum();
       } else {
 	error(errSyntaxWarning, -1, "Bad annotation destination position");
-	goto err1;
+	return;
       }
-      obj2.free();
     }
     if (a->getLength() < 5) {
       changeZoom = gFalse;
     } else {
-      a->get(4, &obj2);
+      Object obj2 = a->get(4);
       if (obj2.isNull()) {
 	changeZoom = gFalse;
       } else if (obj2.isNum()) {
@@ -224,9 +210,8 @@
 	changeZoom = (zoom == 0) ? gFalse : gTrue;
       } else {
 	error(errSyntaxWarning, -1, "Bad annotation destination position");
-	goto err1;
+	return;
       }
-      obj2.free();
     }
 
   // Fit link
@@ -239,7 +224,7 @@
     if (a->getLength() < 3) {
       changeTop = gFalse;
     } else {
-      a->get(2, &obj2);
+      Object obj2 = a->get(2);
       if (obj2.isNull()) {
 	changeTop = gFalse;
       } else if (obj2.isNum()) {
@@ -249,17 +234,16 @@
 	error(errSyntaxWarning, -1, "Bad annotation destination position");
 	kind = destFit;
       }
-      obj2.free();
     }
 
   // FitV link
   } else if (obj1.isName("FitV")) {
     if (a->getLength() < 3) {
       error(errSyntaxWarning, -1, "Annotation destination array is too short");
-      goto err2;
+      return;
     }
     kind = destFitV;
-    a->get(2, &obj2);
+    Object obj2 = a->get(2);
     if (obj2.isNull()) {
       changeLeft = gFalse;
     } else if (obj2.isNum()) {
@@ -269,43 +253,42 @@
       error(errSyntaxWarning, -1, "Bad annotation destination position");
       kind = destFit;
     }
-    obj2.free();
 
   // FitR link
   } else if (obj1.isName("FitR")) {
     if (a->getLength() < 6) {
       error(errSyntaxWarning, -1, "Annotation destination array is too short");
-      goto err2;
+      return;
     }
     kind = destFitR;
-    if (a->get(2, &obj2)->isNum()) {
+    Object obj2 = a->get(2);
+    if (obj2.isNum()) {
       left = obj2.getNum();
     } else {
       error(errSyntaxWarning, -1, "Bad annotation destination position");
       kind = destFit;
     }
-    obj2.free();
-    if (a->get(3, &obj2)->isNum()) {
+    obj2 = a->get(3);
+    if (obj2.isNum()) {
       bottom = obj2.getNum();
     } else {
       error(errSyntaxWarning, -1, "Bad annotation destination position");
       kind = destFit;
     }
-    obj2.free();
-    if (a->get(4, &obj2)->isNum()) {
+    obj2 = a->get(4);
+    if (obj2.isNum()) {
       right = obj2.getNum();
     } else {
       error(errSyntaxWarning, -1, "Bad annotation destination position");
       kind = destFit;
     }
-    obj2.free();
-    if (a->get(5, &obj2)->isNum()) {
+    obj2 = a->get(5);
+    if (obj2.isNum()) {
       top = obj2.getNum();
     } else {
       error(errSyntaxWarning, -1, "Bad annotation destination position");
       kind = destFit;
     }
-    obj2.free();
 
   // FitB link
   } else if (obj1.isName("FitB")) {
@@ -315,10 +298,10 @@
   } else if (obj1.isName("FitBH")) {
     if (a->getLength() < 3) {
       error(errSyntaxWarning, -1, "Annotation destination array is too short");
-      goto err2;
+      return;
     }
     kind = destFitBH;
-    a->get(2, &obj2);
+    Object obj2 = a->get(2);
     if (obj2.isNull()) {
       changeTop = gFalse;
     } else if (obj2.isNum()) {
@@ -328,16 +311,15 @@
       error(errSyntaxWarning, -1, "Bad annotation destination position");
       kind = destFit;
     }
-    obj2.free();
 
   // FitBV link
   } else if (obj1.isName("FitBV")) {
     if (a->getLength() < 3) {
       error(errSyntaxWarning, -1, "Annotation destination array is too short");
-      goto err2;
+      return;
     }
     kind = destFitBV;
-    a->get(2, &obj2);
+    Object obj2 = a->get(2);
     if (obj2.isNull()) {
       changeLeft = gFalse;
     } else if (obj2.isNum()) {
@@ -347,22 +329,14 @@
       error(errSyntaxWarning, -1, "Bad annotation destination position");
       kind = destFit;
     }
-    obj2.free();
 
   // unknown link kind
   } else {
     error(errSyntaxWarning, -1, "Unknown annotation destination type");
-    goto err2;
   }
 
-  obj1.free();
   ok = gTrue;
   return;
-
- err1:
-  obj2.free();
- err2:
-  obj1.free();
 }
 
 LinkDest::LinkDest(LinkDest *dest) {
@@ -428,10 +402,9 @@
   namedDest = NULL;
 
   // get file name
-  Object obj1;
-  if (getFileSpecNameForPlatform (fileSpecObj, &obj1)) {
+  Object obj1 = getFileSpecNameForPlatform (fileSpecObj);
+  if (obj1.isString()) {
     fileName = obj1.getString()->copy();
-    obj1.free();
   }
 
   // named destination
@@ -469,54 +442,49 @@
 //------------------------------------------------------------------------
 
 LinkLaunch::LinkLaunch(Object *actionObj) {
-  Object obj1, obj2, obj3;
 
   fileName = NULL;
   params = NULL;
 
   if (actionObj->isDict()) {
-    if (!actionObj->dictLookup("F", &obj1)->isNull()) {
-      if (getFileSpecNameForPlatform (&obj1, &obj3)) {
+    Object obj1 = actionObj->dictLookup("F");
+    if (!obj1.isNull()) {
+      Object obj3 = getFileSpecNameForPlatform (&obj1);
+      if (obj3.isString()) {
 	fileName = obj3.getString()->copy();
-	obj3.free();
       }
     } else {
-      obj1.free();
 #ifdef _WIN32
       if (actionObj->dictLookup("Win", &obj1)->isDict()) {
 	obj1.dictLookup("F", &obj2);
 	if (getFileSpecNameForPlatform (&obj2, &obj3)) {
 	  fileName = obj3.getString()->copy();
-	  obj3.free();
 	}
-	obj2.free();
 	if (obj1.dictLookup("P", &obj2)->isString()) {
 	  params = obj2.getString()->copy();
 	}
-	obj2.free();
       } else {
 	error(errSyntaxWarning, -1, "Bad launch-type link action");
       }
 #else
       //~ This hasn't been defined by Adobe yet, so assume it looks
       //~ just like the Win dictionary until they say otherwise.
-      if (actionObj->dictLookup("Unix", &obj1)->isDict()) {
-	obj1.dictLookup("F", &obj2);
-	if (getFileSpecNameForPlatform (&obj2, &obj3)) {
+      obj1 = actionObj->dictLookup("Unix");
+      if (obj1.isDict()) {
+	Object obj2 = obj1.dictLookup("F");
+	Object obj3 = getFileSpecNameForPlatform (&obj2);
+	if (obj3.isString()) {
 	  fileName = obj3.getString()->copy();
-	  obj3.free();
 	}
-	obj2.free();
-	if (obj1.dictLookup("P", &obj2)->isString()) {
+	obj2 = obj1.dictLookup("P");
+	if (obj2.isString()) {
 	  params = obj2.getString()->copy();
 	}
-	obj2.free();
       } else {
 	error(errSyntaxWarning, -1, "Bad launch-type link action");
       }
 #endif
     }
-    obj1.free();
   }
 }
 
@@ -601,23 +569,23 @@
   annotRef.num = -1;
   annotTitle = NULL;
 
-  Object tmp;
-  if (obj->dictLookupNF("Annotation", &tmp)->isRef()) {
+  Object tmp = obj->dictLookupNF("Annotation");
+  if (tmp.isRef()) {
     annotRef = tmp.getRef();
   }
-  tmp.free();
 
-  if (obj->dictLookup("T", &tmp)->isString()) {
+  tmp = obj->dictLookup("T");
+  if (tmp.isString()) {
     annotTitle = tmp.getString()->copy();
   }
-  tmp.free();
 
   if ((annotTitle == NULL) && (annotRef.num == -1)) {
     error(errSyntaxError, -1,
 	  "Movie action is missing both the Annot and T keys");
   }
 
-  if (obj->dictLookup("Operation", &tmp)->isName()) {
+  tmp = obj->dictLookup("Operation");
+  if (tmp.isName()) {
     char *name = tmp.getName();
     
     if (!strcmp(name, "Play")) {
@@ -633,7 +601,6 @@
       operation = operationTypeResume;
     }
   }
-  tmp.free();
 }
 
 LinkMovie::~LinkMovie() {
@@ -654,35 +621,29 @@
   sound = NULL;
   if (soundObj->isDict())
   {
-    Object tmp;
     // volume
-    soundObj->dictLookup("Volume", &tmp);
+    Object tmp = soundObj->dictLookup("Volume");
     if (tmp.isNum()) {
       volume = tmp.getNum();
     }
-    tmp.free();
     // sync
-    soundObj->dictLookup("Synchronous", &tmp);
+    tmp = soundObj->dictLookup("Synchronous");
     if (tmp.isBool()) {
       sync = tmp.getBool();
     }
-    tmp.free();
     // repeat
-    soundObj->dictLookup("Repeat", &tmp);
+    tmp = soundObj->dictLookup("Repeat");
     if (tmp.isBool()) {
       repeat = tmp.getBool();
     }
-    tmp.free();
     // mix
-    soundObj->dictLookup("Mix", &tmp);
+    tmp = soundObj->dictLookup("Mix");
     if (tmp.isBool()) {
       mix = tmp.getBool();
     }
-    tmp.free();
     // 'Sound' object
-    soundObj->dictLookup("Sound", &tmp);
+    tmp = soundObj->dictLookup("Sound");
     sound = Sound::parseSound(&tmp);
-    tmp.free();
   }
 }
 
@@ -701,9 +662,8 @@
   int operationCode = -1;
 
   if (obj->isDict()) {
-    Object tmp;
-
-    if (!obj->dictLookup("JS", &tmp)->isNull()) {
+    Object tmp = obj->dictLookup("JS");
+    if (!tmp.isNull()) {
       if (tmp.isString()) {
         js = new GooString(tmp.getString());
       } else if (tmp.isStream()) {
@@ -714,9 +674,9 @@
         error(errSyntaxWarning, -1, "Invalid Rendition Action: JS not string or stream");
       }
     }
-    tmp.free();
 
-    if (obj->dictLookup("OP", &tmp)->isInt()) {
+    tmp = obj->dictLookup("OP");
+    if (tmp.isInt()) {
       operationCode = tmp.getInt();
       if (!js && (operationCode < 0 || operationCode > 4)) {
         error(errSyntaxWarning, -1, "Invalid Rendition Action: unrecognized operation valued: {0:d}", operationCode);
@@ -724,16 +684,18 @@
         Object obj1;
 
         // retrieve rendition object
-        if (obj->dictLookup("R", &renditionObj)->isDict()) {
+        renditionObj = obj->dictLookup("R");
+        if (renditionObj.isDict()) {
           media = new MediaRendition(&renditionObj);
 	} else if (operationCode == 0 || operationCode == 4) {
           error(errSyntaxWarning, -1, "Invalid Rendition Action: no R field with op = {0:d}", operationCode);
-	  renditionObj.free();
+	  renditionObj.setToNull();
 	}
 
-	if (!obj->dictLookupNF("AN", &screenRef)->isRef() && operation >= 0 && operation <= 4) {
+	screenRef = obj->dictLookupNF("AN");
+	if (!screenRef.isRef() && operation >= 0 && operation <= 4) {
 	  error(errSyntaxWarning, -1, "Invalid Rendition Action: no AN field with op = {0:d}", operationCode);
-	  screenRef.free();
+	  screenRef.setToNull();
 	}
       }
 
@@ -757,18 +719,12 @@
     } else if (!js) {
       error(errSyntaxWarning, -1, "Invalid Rendition action: no OP or JS field defined");
     }
-    tmp.free();
   }
 }
 
 LinkRendition::~LinkRendition() {
-  renditionObj.free();
-  screenRef.free();
-
-  if (js)
-    delete js;
-  if (media)
-    delete media;
+  delete js;
+  delete media;
 }
 
 
@@ -799,18 +755,15 @@
 // LinkOCGState
 //------------------------------------------------------------------------
 LinkOCGState::LinkOCGState(Object *obj) {
-  Object obj1;
-
   stateList = new GooList();
   preserveRB = gTrue;
 
-  if (obj->dictLookup("State", &obj1)->isArray()) {
+  Object obj1 = obj->dictLookup("State");
+  if (obj1.isArray()) {
     StateList *stList = NULL;
 
     for (int i = 0; i < obj1.arrayGetLength(); ++i) {
-      Object obj2;
-
-      obj1.arrayGetNF(i, &obj2);
+      Object obj2 = obj1.arrayGetNF(i);
       if (obj2.isName()) {
         if (stList)
 	  stateList->append(stList);
@@ -842,7 +795,6 @@
       } else {
         error(errSyntaxWarning, -1, "Invalid item in OCG Action State array");
       }
-      obj2.free();
     }
     // Add the last group
     if (stList)
@@ -852,12 +804,11 @@
     delete stateList;
     stateList = NULL;
   }
-  obj1.free();
 
-  if (obj->dictLookup("PreserveRB", &obj1)->isBool()) {
+  obj1 = obj->dictLookup("PreserveRB");
+  if (obj1.isBool()) {
     preserveRB = obj1.getBool();
   }
-  obj1.free();
 }
 
 LinkOCGState::~LinkOCGState() {
diff --git a/poppler/Movie.cc b/poppler/Movie.cc
index f68b6ad..fa709b3 100644
--- a/poppler/Movie.cc
+++ b/poppler/Movie.cc
@@ -6,7 +6,7 @@
 // Hugo Mercier <hmercier31[at]gmail.com> (c) 2008
 // Pino Toscano <pino@kde.org> (c) 2008
 // Carlos Garcia Campos <carlosgc@gnome.org> (c) 2010
-// Albert Astals Cid <aacid@kde.org> (c) 2010
+// Albert Astals Cid <aacid@kde.org> (c) 2010, 2017
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License as published by
@@ -47,9 +47,8 @@
 }
 
 void MovieActivationParameters::parseMovieActivation(Object* aDict) {
-  Object obj1;
-
-  if (!aDict->dictLookup("Start", &obj1)->isNull()) {
+  Object obj1 = aDict->dictLookup("Start");
+  if (obj1.isNull()) {
     if (obj1.isInt()) {
       // If it is representable as an integer (subject to the implementation limit for
       // integers, as described in Appendix C), it should be specified as such.
@@ -64,26 +63,23 @@
     } else if (obj1.isArray()) {
       Array* a = obj1.getArray();
 
-      Object tmp;
-      a->get(0, &tmp);
+      Object tmp = a->get(0);
       if (tmp.isInt()) {
         start.units = tmp.getInt();
       }
       if (tmp.isString()) {
         // UNSUPPORTED
       }
-      tmp.free();
 
-      a->get(1, &tmp);
+      tmp = a->get(1);
       if (tmp.isInt()) {
         start.units_per_second = tmp.getInt();
       }
-      tmp.free();
     }
   }
-  obj1.free();
 
-  if (!aDict->dictLookup("Duration", &obj1)->isNull()) {
+  obj1 = aDict->dictLookup("Duration");
+  if (obj1.isNull()) {
     if (obj1.isInt()) {
       duration.units = obj1.getInt();
     } else if (obj1.isString()) {
@@ -91,47 +87,44 @@
     } else if (obj1.isArray()) {
       Array* a = obj1.getArray();
 
-      Object tmp;
-      a->get(0, &tmp);
+      Object tmp = a->get(0);
       if (tmp.isInt()) {
         duration.units = tmp.getInt();
       }
       if (tmp.isString()) {
         // UNSUPPORTED
       }
-      tmp.free();
 
-      a->get(1, &tmp);
+      tmp = a->get(1);
       if (tmp.isInt()) {
         duration.units_per_second = tmp.getInt();
       }
-      tmp.free();
     }
   }
-  obj1.free();
 
-  if (aDict->dictLookup("Rate", &obj1)->isNum()) {
+  obj1 = aDict->dictLookup("Rate");
+  if (obj1.isNum()) {
     rate = obj1.getNum();
   }
-  obj1.free();
 
-  if (aDict->dictLookup("Volume", &obj1)->isNum()) {
+  obj1 = aDict->dictLookup("Volume");
+  if (obj1.isNum()) {
     // convert volume to [0 100]
     volume = int((obj1.getNum() + 1.0) * 50);
   }
-  obj1.free();
 
-  if (aDict->dictLookup("ShowControls", &obj1)->isBool()) {
+  obj1 = aDict->dictLookup("ShowControls");
+  if (obj1.isBool()) {
     showControls = obj1.getBool();
   }
-  obj1.free();
 
-  if (aDict->dictLookup("Synchronous", &obj1)->isBool()) {
+  obj1 = aDict->dictLookup("Synchronous");
+  if (obj1.isBool()) {
     synchronousPlay = obj1.getBool();
   }
-  obj1.free();
 
-  if (aDict->dictLookup("Mode", &obj1)->isName()) {
+  obj1 = aDict->dictLookup("Mode");
+  if (obj1.isName()) {
     char* name = obj1.getName();
     if (!strcmp(name, "Once")) {
       repeatMode = repeatModeOnce;
@@ -143,43 +136,40 @@
       repeatMode = repeatModePalindrome;
     }
   }
-  obj1.free();
 
-  if (aDict->dictLookup("FWScale", &obj1)->isArray()) {
+  obj1 = aDict->dictLookup("FWScale");
+  if (obj1.isArray()) {
     // the presence of that entry implies that the movie is to be played
     // in a floating window
     floatingWindow = gTrue;
 
     Array* scale = obj1.getArray();
     if (scale->getLength() >= 2) {
-      Object tmp;
-      if (scale->get(0, &tmp)->isInt()) {
+      Object tmp = scale->get(1);
+      if (tmp.isInt()) {
         znum = tmp.getInt();
       }
-      tmp.free();
-      if (scale->get(1, &tmp)->isInt()) {
+      tmp = scale->get(1);
+      if (tmp.isInt()) {
         zdenum = tmp.getInt();
       }
-      tmp.free();
     }
   }
-  obj1.free();
 
-  if (aDict->dictLookup("FWPosition", &obj1)->isArray()) {
+  obj1 = aDict->dictLookup("FWPosition");
+  if (obj1.isArray()) {
     Array* pos = obj1.getArray();
     if (pos->getLength() >= 2) {
-      Object tmp;
-      if (pos->get(0, &tmp)->isNum()) {
+      Object tmp = pos->get(0);
+      if (tmp.isNum()) {
         xPosition = tmp.getNum();
       }
-      tmp.free();
-      if (pos->get(1, &tmp)->isNum()) {
+      tmp = pos->get(1);
+      if (tmp.isNum()) {
         yPosition = tmp.getNum();
       }
-      tmp.free();
     }
   }
-  obj1.free();
 }
 
 void Movie::parseMovie (Object *movieDict) {
@@ -189,59 +179,55 @@
   height = -1;
   showPoster = gFalse;
 
-  Object obj1, obj2;
-  if (getFileSpecNameForPlatform(movieDict->dictLookup("F", &obj1), &obj2)) {
+  Object obj1 = movieDict->dictLookup("F");
+  Object obj2 = getFileSpecNameForPlatform(&obj1);
+  if (obj2.isString()) {
     fileName = obj2.getString()->copy();
-    obj2.free();
   } else {
     error (errSyntaxError, -1, "Invalid Movie");
     ok = gFalse;
-    obj1.free();
     return;
   }
-  obj1.free();
 
-  if (movieDict->dictLookup("Aspect", &obj1)->isArray()) {
+  obj1 = movieDict->dictLookup("Aspect");
+  if (obj1.isArray()) {
     Array* aspect = obj1.getArray();
     if (aspect->getLength() >= 2) {
-      Object tmp;
-      if( aspect->get(0, &tmp)->isNum() ) {
-        width = (int)floor( aspect->get(0, &tmp)->getNum() + 0.5 );
+      Object tmp = aspect->get(0);
+      if( tmp.isNum() ) {
+        width = (int)floor( tmp.getNum() + 0.5 );
       }
-      tmp.free();
-      if( aspect->get(1, &tmp)->isNum() ) {
-        height = (int)floor( aspect->get(1, &tmp)->getNum() + 0.5 );
+      tmp = aspect->get(1);
+      if( tmp.isNum() ) {
+        height = (int)floor( tmp.getNum() + 0.5 );
       }
-      tmp.free();
     }
   }
-  obj1.free();
 
-  if (movieDict->dictLookup("Rotate", &obj1)->isInt()) {
+  obj1 = movieDict->dictLookup("Rotate");
+  if (obj1.isInt()) {
     // round up to 90°
     rotationAngle = (((obj1.getInt() + 360) % 360) % 90) * 90;
   }
-  obj1.free();
 
   //
   // movie poster
   //
-  if (!movieDict->dictLookupNF("Poster", &poster)->isNull()) {
+  poster = movieDict->dictLookupNF("Poster");
+  if (!poster.isNull()) {
     if (poster.isRef() || poster.isStream()) {
       showPoster = gTrue;
     } else if (poster.isBool()) {
       showPoster = poster.getBool();
-      poster.free();
+      poster.setToNull();
     } else {
-      poster.free();
+      poster.setToNull();
     }
   }
 }
 
 Movie::~Movie() {
-  if (fileName)
-    delete fileName;
-  poster.free();
+  delete fileName;
 }
 
 Movie::Movie(Object *movieDict) {
@@ -265,6 +251,23 @@
   }
 }
 
+Movie::Movie(const Movie &other)
+{
+  ok = other.ok;
+  rotationAngle = other.rotationAngle;
+  width = other.width;
+  height = other.height;
+  showPoster = other.showPoster;
+  MA = other.MA;
+
+  poster = other.poster.copy();
+
+  if (other.fileName)
+    fileName = other.fileName->copy();
+  else
+    fileName = nullptr;
+}
+
 void Movie::getFloatingWindowSize(int *widthA, int *heightA)
 {
   *widthA = int(width * double(MA.znum) / MA.zdenum);
@@ -272,14 +275,5 @@
 }
 
 Movie* Movie::copy() {
-
-  // call default copy constructor
-  Movie* new_movie = new Movie(*this);
-
-  if (fileName)
-    new_movie->fileName = fileName->copy();
-
-  poster.copy(&new_movie->poster);
-
-  return new_movie;
+  return new Movie(*this);
 }
diff --git a/poppler/Movie.h b/poppler/Movie.h
index 1a16265..c0fcd8f 100644
--- a/poppler/Movie.h
+++ b/poppler/Movie.h
@@ -5,6 +5,7 @@
 //---------------------------------------------------------------------------------
 // Hugo Mercier <hmercier31[at]gmail.com> (c) 2008
 // Carlos Garcia Campos <carlosgc@gnome.org> (c) 2010
+// Albert Astals Cid <aacid@kde.org> (c) 2017
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License as published by
@@ -71,6 +72,7 @@
  public:
   Movie(Object *objMovie, Object *objAct);
   Movie(Object *objMovie);
+  Movie(const Movie &movie);
   ~Movie();
 
   GBool isOk() { return ok; }
@@ -81,7 +83,7 @@
   Gushort getRotationAngle() { return rotationAngle; }
   void getAspect (int *widthA, int *heightA) { *widthA = width; *heightA = height; }
 
-  Object *getPoster(Object *obj) { return poster.copy(obj); }
+  Object getPoster() { return poster.copy(); }
   GBool getShowPoster() { return showPoster; }
 
   GBool getUseFloatingWindow() { return MA.floatingWindow; }
diff --git a/poppler/Object.cc b/poppler/Object.cc
index d06bb39..4fce012 100644
--- a/poppler/Object.cc
+++ b/poppler/Object.cc
@@ -13,7 +13,7 @@
 // All changes made under the Poppler project to this file are licensed
 // under GPL version 2 or later
 //
-// Copyright (C) 2008, 2010, 2012 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2008, 2010, 2012, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
 //
 // To see a description of the changes please see the Changelog file that
@@ -54,47 +54,48 @@
   "error",
   "eof",
   "none",
-  "integer64"
+  "integer64",
+  "dead"
 };
 
 #ifdef DEBUG_MEM
 int Object::numAlloc[numObjTypes] =
-  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 #endif
 
-Object *Object::initArray(XRef *xref) {
-  initObj(objArray);
-  array = new Array(xref);
-  return this;
+Object::Object(Object&& other)
+{
+  type = other.type;
+  real = other.real; // this is the biggest of the union so it's enough
+  other.type = objDead;
 }
 
-Object *Object::initDict(XRef *xref) {
-  initObj(objDict);
-  dict = new Dict(xref);
-  return this;
+Object& Object::operator=(Object&& other)
+{
+  free();
+  type = other.type;
+  real = other.real; // this is the biggest of the union so it's enough
+  other.type = objDead;
+  return *this;
 }
 
-Object *Object::initDict(Dict *dictA) {
-  initObj(objDict);
-  dict = dictA;
-  dict->incRef();
-  return this;
+Object::~Object()
+{
+  free();
 }
 
-Object *Object::initStream(Stream *streamA) {
-  initObj(objStream);
-  stream = streamA;
-  return this;
-}
+Object Object::copy() const {
+  CHECK_NOT_DEAD;
 
-Object *Object::copy(Object *obj) {
-  *obj = *this;
+  Object obj;
+  obj.type = type;
+  obj.real = real; // this is the biggest of the union so it's enough
   switch (type) {
   case objString:
-    obj->string = string->copy();
+    obj.string = string->copy();
     break;
   case objName:
-    obj->name = copyString(name);
+    obj.cString = copyString(cString);
     break;
   case objArray:
     array->incRef();
@@ -106,7 +107,7 @@
     stream->incRef();
     break;
   case objCmd:
-    obj->cmd = copyString(cmd);
+    obj.cString = copyString(cString);
     break;
   default:
     break;
@@ -117,9 +118,11 @@
   return obj;
 }
 
-Object *Object::fetch(XRef *xref, Object *obj, int recursion) {
+Object Object::fetch(XRef *xref, int recursion) const {
+  CHECK_NOT_DEAD;
+
   return (type == objRef && xref) ?
-         xref->fetch(ref.num, ref.gen, obj, recursion) : copy(obj);
+         xref->fetch(ref.num, ref.gen, recursion) : copy();
 }
 
 void Object::free() {
@@ -128,7 +131,7 @@
     delete string;
     break;
   case objName:
-    gfree(name);
+    gfree(cString);
     break;
   case objArray:
     if (!array->decRef()) {
@@ -146,7 +149,7 @@
     }
     break;
   case objCmd:
-    gfree(cmd);
+    gfree(cString);
     break;
   default:
     break;
@@ -181,7 +184,7 @@
     fprintf(f, ")");
     break;
   case objName:
-    fprintf(f, "/%s", name);
+    fprintf(f, "/%s", cString);
     break;
   case objNull:
     fprintf(f, "null");
@@ -191,9 +194,8 @@
     for (i = 0; i < arrayGetLength(); ++i) {
       if (i > 0)
 	fprintf(f, " ");
-      arrayGetNF(i, &obj);
+      obj = arrayGetNF(i);
       obj.print(f);
-      obj.free();
     }
     fprintf(f, "]");
     break;
@@ -201,9 +203,8 @@
     fprintf(f, "<<");
     for (i = 0; i < dictGetLength(); ++i) {
       fprintf(f, " /%s ", dictGetKey(i));
-      dictGetValNF(i, &obj);
+      obj = dictGetValNF(i);
       obj.print(f);
-      obj.free();
     }
     fprintf(f, " >>");
     break;
@@ -214,7 +215,7 @@
     fprintf(f, "%d %d R", ref.num, ref.gen);
     break;
   case objCmd:
-    fprintf(f, "%s", cmd);
+    fprintf(f, "%s", cString);
     break;
   case objError:
     fprintf(f, "<error>");
@@ -225,6 +226,9 @@
   case objNone:
     fprintf(f, "<none>");
     break;
+    case objDead:
+    fprintf(f, "<dead>");
+    break;
   case objInt64:
     fprintf(f, "%lld", int64g);
     break;
diff --git a/poppler/Object.h b/poppler/Object.h
index 18c4558..23c98a9 100644
--- a/poppler/Object.h
+++ b/poppler/Object.h
@@ -65,6 +65,12 @@
         abort(); \
     }
 
+#define CHECK_NOT_DEAD \
+  if (unlikely(type == objDead)) { \
+        error(errInternal, 0, "Call to dead object"); \
+        abort(); \
+    }
+
 class XRef;
 class Array;
 class Dict;
@@ -105,99 +111,105 @@
   objNone,			// uninitialized object
 
   // poppler-only objects
-  objInt64			// integer with at least 64-bits
+  objInt64,			// integer with at least 64-bits
+  objDead			// and object after shallowCopy
 };
 
-#define numObjTypes 15		// total number of object types
+#define numObjTypes 16		// total number of object types
 
 //------------------------------------------------------------------------
 // Object
 //------------------------------------------------------------------------
 
 #ifdef DEBUG_MEM
-#define initObj(t) zeroUnion(); ++numAlloc[type = t]
+#define initObj(t) free(); zeroUnion(); ++numAlloc[type = t]
 #else
-#define initObj(t) zeroUnion(); type = t
+#define initObj(t) free(); zeroUnion(); type = t
+#endif
+
+#ifdef DEBUG_MEM
+#define constructObj(t) ++numAlloc[type = t]
+#else
+#define constructObj(t) type = t
 #endif
 
 class Object {
 public:
   // clear the anonymous union as best we can -- clear at least a pointer
-  void zeroUnion() { this->name = NULL; }
+  void zeroUnion() { this->cString = NULL; }
 
   // Default constructor.
   Object():
     type(objNone) { zeroUnion(); }
+  ~Object();
 
-  // Initialize an object.
-  Object *initBool(GBool boolnA)
-    { initObj(objBool); booln = boolnA; return this; }
-  Object *initInt(int intgA)
-    { initObj(objInt); intg = intgA; return this; }
-  Object *initReal(double realA)
-    { initObj(objReal); real = realA; return this; }
-  Object *initString(GooString *stringA)
-    { initObj(objString); string = stringA; return this; }
-  Object *initName(const char *nameA)
-    { initObj(objName); name = copyString(nameA); return this; }
-  Object *initNull()
-    { initObj(objNull); return this; }
-  Object *initArray(XRef *xref);
-  Object *initDict(XRef *xref);
-  Object *initDict(Dict *dictA);
-  Object *initStream(Stream *streamA);
-  Object *initRef(int numA, int genA)
-    { initObj(objRef); ref.num = numA; ref.gen = genA; return this; }
-  Object *initCmd(char *cmdA)
-    { initObj(objCmd); cmd = copyString(cmdA); return this; }
-  Object *initError()
-    { initObj(objError); return this; }
-  Object *initEOF()
-    { initObj(objEOF); return this; }
-  Object *initInt64(long long int64gA)
-    { initObj(objInt64); int64g = int64gA; return this; }
+  explicit Object(GBool boolnA)
+    { constructObj(objBool); booln = boolnA; }
+  explicit Object(int intgA)
+    { constructObj(objInt); intg = intgA; }
+  explicit Object(ObjType typeA)
+    { constructObj(typeA); }
+  explicit Object(double realA)
+    { constructObj(objReal); real = realA; }
+  explicit Object(GooString *stringA)
+    { constructObj(objString); string = stringA; }
+  Object(ObjType typeA, const char *stringA)
+    { constructObj(typeA); cString = copyString(stringA); }
+  explicit Object(long long int64gA)
+    { constructObj(objInt64); int64g = int64gA; }
+  explicit Object(Array *arrayA)
+    { constructObj(objArray); array = arrayA; }
+  explicit Object(Dict *dictA)
+    { constructObj(objDict); dict = dictA; }
+  explicit Object(Stream *streamA)
+    { constructObj(objStream); stream = streamA; }
+  Object(int numA, int genA)
+    { constructObj(objRef); ref.num = numA; ref.gen = genA; }
+  template<typename T> Object(T) = delete;
 
-  // Copy an object.
-  Object *copy(Object *obj);
-  Object *shallowCopy(Object *obj) {
-    *obj = *this;
-    return obj;
-  }
+  Object(Object&& other);
+  Object& operator=(Object&& other);
+
+  Object &operator=(const Object &other) = delete;
+  Object(const Object &other) = delete;
+
+  // Set object to null.
+  void setToNull() { initObj(objNull); }
+
+  // Copy this to obj
+  Object copy() const;
 
   // If object is a Ref, fetch and return the referenced object.
   // Otherwise, return a copy of the object.
-  Object *fetch(XRef *xref, Object *obj, int recursion = 0);
-
-  // Free object contents.
-  void free();
+  Object fetch(XRef *xref, int recursion = 0) const;
 
   // Type checking.
-  ObjType getType() { return type; }
-  GBool isBool() { return type == objBool; }
-  GBool isInt() { return type == objInt; }
-  GBool isReal() { return type == objReal; }
-  GBool isNum() { return type == objInt || type == objReal || type == objInt64; }
-  GBool isString() { return type == objString; }
-  GBool isName() { return type == objName; }
-  GBool isNull() { return type == objNull; }
-  GBool isArray() { return type == objArray; }
-  GBool isDict() { return type == objDict; }
-  GBool isStream() { return type == objStream; }
-  GBool isRef() { return type == objRef; }
-  GBool isCmd() { return type == objCmd; }
-  GBool isError() { return type == objError; }
-  GBool isEOF() { return type == objEOF; }
-  GBool isNone() { return type == objNone; }
-  GBool isInt64() { return type == objInt64; }
-  GBool isIntOrInt64() { return type == objInt || type == objInt64; }
+  ObjType getType() { CHECK_NOT_DEAD; return type; }
+  GBool isBool() { CHECK_NOT_DEAD; return type == objBool; }
+  GBool isInt() { CHECK_NOT_DEAD; return type == objInt; }
+  GBool isReal() { CHECK_NOT_DEAD; return type == objReal; }
+  GBool isNum() { CHECK_NOT_DEAD; return type == objInt || type == objReal || type == objInt64; }
+  GBool isString() { CHECK_NOT_DEAD; return type == objString; }
+  GBool isName() { CHECK_NOT_DEAD; return type == objName; }
+  GBool isNull() { CHECK_NOT_DEAD; return type == objNull; }
+  GBool isArray() { CHECK_NOT_DEAD; return type == objArray; }
+  GBool isDict() { CHECK_NOT_DEAD; return type == objDict; }
+  GBool isStream() { CHECK_NOT_DEAD; return type == objStream; }
+  GBool isRef() { CHECK_NOT_DEAD; return type == objRef; }
+  GBool isCmd() { CHECK_NOT_DEAD; return type == objCmd; }
+  GBool isError() { CHECK_NOT_DEAD; return type == objError; }
+  GBool isEOF() { CHECK_NOT_DEAD; return type == objEOF; }
+  GBool isNone() { CHECK_NOT_DEAD; return type == objNone; }
+  GBool isInt64() { CHECK_NOT_DEAD; return type == objInt64; }
+  GBool isIntOrInt64() { CHECK_NOT_DEAD; return type == objInt || type == objInt64; }
 
   // Special type checking.
   GBool isName(const char *nameA)
-    { return type == objName && !strcmp(name, nameA); }
+    { return type == objName && !strcmp(cString, nameA); }
   GBool isDict(const char *dictType);
   GBool isStream(char *dictType);
   GBool isCmd(const char *cmdA)
-    { return type == objCmd && !strcmp(cmd, cmdA); }
+    { return type == objCmd && !strcmp(cString, cmdA); }
 
   // Accessors.
   GBool getBool() { OBJECT_TYPE_CHECK(objBool); return booln; }
@@ -220,36 +232,36 @@
   // because the object it's not expected to have a NULL string.
   GooString *takeString() {
     OBJECT_TYPE_CHECK(objString); GooString *s = string; string = NULL; return s; }
-  char *getName() { OBJECT_TYPE_CHECK(objName); return name; }
+  char *getName() { OBJECT_TYPE_CHECK(objName); return cString; }
   Array *getArray() { OBJECT_TYPE_CHECK(objArray); return array; }
   Dict *getDict() { OBJECT_TYPE_CHECK(objDict); return dict; }
   Stream *getStream() { OBJECT_TYPE_CHECK(objStream); return stream; }
   Ref getRef() { OBJECT_TYPE_CHECK(objRef); return ref; }
   int getRefNum() { OBJECT_TYPE_CHECK(objRef); return ref.num; }
   int getRefGen() { OBJECT_TYPE_CHECK(objRef); return ref.gen; }
-  char *getCmd() { OBJECT_TYPE_CHECK(objCmd); return cmd; }
+  char *getCmd() { OBJECT_TYPE_CHECK(objCmd); return cString; }
   long long getInt64() { OBJECT_TYPE_CHECK(objInt64); return int64g; }
   long long getIntOrInt64() { OBJECT_2TYPES_CHECK(objInt, objInt64);
     return type == objInt ? intg : int64g; }
 
   // Array accessors.
   int arrayGetLength();
-  void arrayAdd(Object *elem);
+  void arrayAdd(Object &&elem);
   void arrayRemove(int i);
-  Object *arrayGet(int i, Object *obj, int recursion);
-  Object *arrayGetNF(int i, Object *obj);
+  Object arrayGet(int i, int recursion);
+  Object arrayGetNF(int i);
 
   // Dict accessors.
   int dictGetLength();
-  void dictAdd(char *key, Object *val);
-  void dictSet(const char *key, Object *val);
+  void dictAdd(char *key, Object &&val);
+  void dictSet(const char *key, Object &&val);
   void dictRemove(const char *key);
   GBool dictIs(const char *dictType);
-  Object *dictLookup(const char *key, Object *obj, int recursion = 0);
-  Object *dictLookupNF(const char *key, Object *obj);
+  Object dictLookup(const char *key, int recursion = 0);
+  Object dictLookupNF(const char *key);
   char *dictGetKey(int i);
-  Object *dictGetVal(int i, Object *obj);
-  Object *dictGetValNF(int i, Object *obj);
+  Object dictGetVal(int i);
+  Object dictGetValNF(int i);
 
   // Stream accessors.
   GBool streamIs(char *dictType);
@@ -271,6 +283,15 @@
   static void memCheck(FILE *f);
 
 private:
+  friend class Array; // Needs free and initNullAfterMalloc
+  friend class Dict; // Needs free and initNullAfterMalloc
+  friend class XRef; // Needs free and initNullAfterMalloc
+
+  // Free object contents.
+  void free();
+
+  // Only use if are mallocing Objects
+  void initNullAfterMalloc() { constructObj(objNull); }
 
   ObjType type;			// object type
   union {			// value for each type:
@@ -279,12 +300,11 @@
     long long int64g;           //   64-bit integer
     double real;		//   real
     GooString *string;		//   string
-    char *name;			//   name
+    char *cString;		//   name or command, depending on objType
     Array *array;		//   array
     Dict *dict;			//   dictionary
     Stream *stream;		//   stream
     Ref ref;			//   indirect reference
-    char *cmd;			//   command
   };
 
 #ifdef DEBUG_MEM
@@ -302,17 +322,17 @@
 inline int Object::arrayGetLength()
   { OBJECT_TYPE_CHECK(objArray); return array->getLength(); }
 
-inline void Object::arrayAdd(Object *elem)
-  { OBJECT_TYPE_CHECK(objArray); array->add(elem); }
+inline void Object::arrayAdd(Object &&elem)
+  { OBJECT_TYPE_CHECK(objArray); array->add(std::move(elem)); }
 
 inline void Object::arrayRemove(int i)
   { OBJECT_TYPE_CHECK(objArray); array->remove(i); }
 
-inline Object *Object::arrayGet(int i, Object *obj, int recursion = 0)
-  { OBJECT_TYPE_CHECK(objArray); return array->get(i, obj, recursion); }
+inline Object Object::arrayGet(int i, int recursion = 0)
+  { OBJECT_TYPE_CHECK(objArray); return array->get(i, recursion); }
 
-inline Object *Object::arrayGetNF(int i, Object *obj)
-  { OBJECT_TYPE_CHECK(objArray); return array->getNF(i, obj); }
+inline Object Object::arrayGetNF(int i)
+  { OBJECT_TYPE_CHECK(objArray); return array->getNF(i); }
 
 //------------------------------------------------------------------------
 // Dict accessors.
@@ -323,11 +343,11 @@
 inline int Object::dictGetLength()
   { OBJECT_TYPE_CHECK(objDict); return dict->getLength(); }
 
-inline void Object::dictAdd(char *key, Object *val)
-  { OBJECT_TYPE_CHECK(objDict); dict->add(key, val); }
+inline void Object::dictAdd(char *key, Object &&val)
+  { OBJECT_TYPE_CHECK(objDict); dict->add(key, std::move(val)); }
 
-inline void Object::dictSet(const char *key, Object *val)
-  { OBJECT_TYPE_CHECK(objDict); dict->set(key, val); }
+inline void Object::dictSet(const char *key, Object &&val)
+  { OBJECT_TYPE_CHECK(objDict); dict->set(key, std::move(val)); }
 
 inline void Object::dictRemove(const char *key)
   { OBJECT_TYPE_CHECK(objDict); dict->remove(key); }
@@ -338,20 +358,20 @@
 inline GBool Object::isDict(const char *dictType)
   { return type == objDict && dictIs(dictType); }
 
-inline Object *Object::dictLookup(const char *key, Object *obj, int recursion)
-  { OBJECT_TYPE_CHECK(objDict); return dict->lookup(key, obj, recursion); }
+inline Object Object::dictLookup(const char *key, int recursion)
+  { OBJECT_TYPE_CHECK(objDict); return dict->lookup(key, recursion); }
 
-inline Object *Object::dictLookupNF(const char *key, Object *obj)
-  { OBJECT_TYPE_CHECK(objDict); return dict->lookupNF(key, obj); }
+inline Object Object::dictLookupNF(const char *key)
+  { OBJECT_TYPE_CHECK(objDict); return dict->lookupNF(key); }
 
 inline char *Object::dictGetKey(int i)
   { OBJECT_TYPE_CHECK(objDict); return dict->getKey(i); }
 
-inline Object *Object::dictGetVal(int i, Object *obj)
-  { OBJECT_TYPE_CHECK(objDict); return dict->getVal(i, obj); }
+inline Object Object::dictGetVal(int i)
+  { OBJECT_TYPE_CHECK(objDict); return dict->getVal(i); }
 
-inline Object *Object::dictGetValNF(int i, Object *obj)
-  { OBJECT_TYPE_CHECK(objDict); return dict->getValNF(i, obj); }
+inline Object Object::dictGetValNF(int i)
+  { OBJECT_TYPE_CHECK(objDict); return dict->getValNF(i); }
 
 //------------------------------------------------------------------------
 // Stream accessors.
diff --git a/poppler/OptionalContent.cc b/poppler/OptionalContent.cc
index 44eef19..d2e878e 100644
--- a/poppler/OptionalContent.cc
+++ b/poppler/OptionalContent.cc
@@ -43,50 +43,40 @@
   optionalContentGroups = new GooList();
   display = NULL;
 
-  Object ocgList;
-  ocgObject->dictLookup("OCGs", &ocgList);
+  Object ocgList = ocgObject->dictLookup("OCGs");
   if (!ocgList.isArray()) {
     error(errSyntaxError, -1, "Expected the optional content group list, but wasn't able to find it, or it isn't an Array");
-    ocgList.free();
     ok = gFalse;
     return;
   }
 
   // we now enumerate over the ocgList, and build up the optionalContentGroups list.
   for(int i = 0; i < ocgList.arrayGetLength(); ++i) {
-    Object ocg;
-    ocgList.arrayGet(i, &ocg);
+    Object ocg = ocgList.arrayGet(i);
     if (!ocg.isDict()) {
-      ocg.free();
       break;
     }
     OptionalContentGroup *thisOptionalContentGroup = new OptionalContentGroup(ocg.getDict());
-    ocg.free();
-    ocgList.arrayGetNF(i, &ocg);
+    ocg = ocgList.arrayGetNF(i);
     if (!ocg.isRef()) {
-      ocg.free();
+      delete thisOptionalContentGroup;
       break;
     }
     // TODO: we should create a lookup map from Ref to the OptionalContentGroup
     thisOptionalContentGroup->setRef( ocg.getRef() );
-    ocg.free();
     // the default is ON - we change state later, depending on BaseState, ON and OFF
     thisOptionalContentGroup->setState(OptionalContentGroup::On);
     optionalContentGroups->append(thisOptionalContentGroup);
   }
 
-  Object defaultOcgConfig;
-  ocgObject->dictLookup("D", &defaultOcgConfig);
+  Object defaultOcgConfig = ocgObject->dictLookup("D");
   if (!defaultOcgConfig.isDict()) {
     error(errSyntaxError, -1, "Expected the default config, but wasn't able to find it, or it isn't a Dictionary");
-    defaultOcgConfig.free();
-    ocgList.free();
     ok = gFalse;
     return;
   }
 
-  Object baseState;
-  defaultOcgConfig.dictLookup("BaseState", &baseState);
+  Object baseState = defaultOcgConfig.dictLookup("BaseState");
   if (baseState.isName("OFF")) {
     for (int i = 0; i < optionalContentGroups->getLength(); ++i) {
       OptionalContentGroup *group;
@@ -95,22 +85,17 @@
       group->setState(OptionalContentGroup::Off);
     }
   }
-  baseState.free();
 
-  Object on;
-  defaultOcgConfig.dictLookup("ON", &on);
+  Object on = defaultOcgConfig.dictLookup("ON");
   if (on.isArray()) {
     // ON is an optional element
     for (int i = 0; i < on.arrayGetLength(); ++i) {
-      Object reference;
-      on.arrayGetNF(i, &reference);
+      Object reference = on.arrayGetNF(i);
       if (!reference.isRef()) {
 	// there can be null entries
-	reference.free();
 	break;
       }
       OptionalContentGroup *group = findOcgByRef( reference.getRef() );
-      reference.free();
       if (!group) {
 	error(errSyntaxWarning, -1, "Couldn't find group for reference");
 	break;
@@ -118,22 +103,17 @@
       group->setState(OptionalContentGroup::On);
     }
   }
-  on.free();
 
-  Object off;
-  defaultOcgConfig.dictLookup("OFF", &off);
+  Object off = defaultOcgConfig.dictLookup("OFF");
   if (off.isArray()) {
     // OFF is an optional element
     for (int i = 0; i < off.arrayGetLength(); ++i) {
-      Object reference;
-      off.arrayGetNF(i, &reference);
+      Object reference = off.arrayGetNF(i);
       if (!reference.isRef()) {
 	// there can be null entries
-	reference.free();
 	break;
       }
       OptionalContentGroup *group = findOcgByRef( reference.getRef() );
-      reference.free();
       if (!group) {
 	error(errSyntaxWarning, -1, "Couldn't find group for reference to set OFF");
 	break;
@@ -141,22 +121,15 @@
       group->setState(OptionalContentGroup::Off);
     }
   }
-  off.free();
 
-  defaultOcgConfig.dictLookup("Order", &order);
-  defaultOcgConfig.dictLookup("RBGroups", &rbgroups);
-
-  ocgList.free();
-  defaultOcgConfig.free();
+  order = defaultOcgConfig.dictLookup("Order");
+  rbgroups = defaultOcgConfig.dictLookup("RBGroups");
 }
 
 OCGs::~OCGs()
 {
   deleteGooList(optionalContentGroups, OptionalContentGroup);
-  order.free();
-  if (display)
-    delete display;
-  rbgroups.free();
+  delete display;
 }
 
 
@@ -193,12 +166,7 @@
 
 bool OCGs::optContentIsVisible( Object *dictRef )
 {
-  Object dictObj;
   Dict *dict;
-  Object dictType;
-  Object ocg;
-  Object policy;
-  Object ve;
   bool result = true;
 
   if (dictRef->isNull())
@@ -210,22 +178,22 @@
       return oc->getState() == OptionalContentGroup::On;
   }
 
-  dictRef->fetch( m_xref, &dictObj );
+  Object dictObj = dictRef->fetch( m_xref);
   if ( ! dictObj.isDict() ) {
     error(errSyntaxWarning, -1, "Unexpected oc reference target: {0:d}", dictObj.getType() );
-    dictObj.free();
     return result;
   }
   dict = dictObj.getDict();
   // printf("checking if optContent is visible\n");
-  dict->lookup("Type", &dictType);
+  Object dictType = dict->lookup("Type");
   if (dictType.isName("OCMD")) {
-    if (dict->lookup("VE", &ve)->isArray()) {
+    Object ve = dict->lookup("VE");
+    if (ve.isArray()) {
       result = evalOCVisibilityExpr(&ve, 0);
     } else {
-      dict->lookupNF("OCGs", &ocg);
+      Object ocg = dict->lookupNF("OCGs");
       if (ocg.isArray()) {
-        dict->lookup("P", &policy);
+        Object policy = dict->lookup("P");
         if (policy.isName("AllOn")) {
           result = allOn( ocg.getArray() );
         } else if (policy.isName("AllOff")) {
@@ -236,7 +204,6 @@
           // this is the default
           result = anyOn( ocg.getArray() );
         }
-        policy.free();
       } else if (ocg.isRef()) {
         OptionalContentGroup *oc = findOcgByRef( ocg.getRef() );
         if ( oc && oc->getState() == OptionalContentGroup::Off ) {
@@ -245,26 +212,20 @@
           result = true ;
         }
       }
-      ocg.free();
     }
-    ve.free();
   } else if ( dictType.isName("OCG") ) {
     OptionalContentGroup* oc = findOcgByRef( dictRef->getRef() );
     if ( oc && oc->getState() == OptionalContentGroup::Off ) {
       result=false;
     }
   }
-  dictType.free();
-  dictObj.free();
   // printf("visibility: %s\n", result? "on" : "off");
   return result;
 }
 
 GBool OCGs::evalOCVisibilityExpr(Object *expr, int recursion) {
   OptionalContentGroup *ocg;
-  Object expr2, op, obj;
   GBool ret;
-  int i;
 
   if (recursion > visibilityExprRecursionLimit) {
     error(errSyntaxError, -1,
@@ -276,19 +237,17 @@
       return ocg->getState() == OptionalContentGroup::On;
     }
   }
-  expr->fetch(m_xref, &expr2);
+  Object expr2 = expr->fetch(m_xref);
   if (!expr2.isArray() || expr2.arrayGetLength() < 1) {
     error(errSyntaxError, -1,
 	  "Invalid optional content visibility expression");
-    expr2.free();
     return gTrue;
   }
-  expr2.arrayGet(0, &op);
+  Object op = expr2.arrayGet(0);
   if (op.isName("Not")) {
     if (expr2.arrayGetLength() == 2) {
-      expr2.arrayGetNF(1, &obj);
+      Object obj = expr2.arrayGetNF(1);
       ret = !evalOCVisibilityExpr(&obj, recursion + 1);
-      obj.free();
     } else {
       error(errSyntaxError, -1,
 	    "Invalid optional content visibility expression");
@@ -296,33 +255,28 @@
     }
   } else if (op.isName("And")) {
     ret = gTrue;
-    for (i = 1; i < expr2.arrayGetLength() && ret; ++i) {
-      expr2.arrayGetNF(i, &obj);
+    for (int i = 1; i < expr2.arrayGetLength() && ret; ++i) {
+      Object obj = expr2.arrayGetNF(i);
       ret = evalOCVisibilityExpr(&obj, recursion + 1);
-      obj.free();
     }
   } else if (op.isName("Or")) {
     ret = gFalse;
-    for (i = 1; i < expr2.arrayGetLength() && !ret; ++i) {
-      expr2.arrayGetNF(i, &obj);
+    for (int i = 1; i < expr2.arrayGetLength() && !ret; ++i) {
+      Object obj = expr2.arrayGetNF(i);
       ret = evalOCVisibilityExpr(&obj, recursion + 1);
-      obj.free();
     }
   } else {
     error(errSyntaxError, -1,
 	  "Invalid optional content visibility expression");
     ret = gTrue;
   }
-  op.free();
-  expr2.free();
   return ret;
 }
 
 bool OCGs::allOn( Array *ocgArray )
 {
   for (int i = 0; i < ocgArray->getLength(); ++i) {
-    Object ocgItem;
-    ocgArray->getNF(i, &ocgItem);
+    Object ocgItem = ocgArray->getNF(i);
     if (ocgItem.isRef()) {
       OptionalContentGroup* oc = findOcgByRef( ocgItem.getRef() );      
       if ( oc && oc->getState() == OptionalContentGroup::Off ) {
@@ -336,8 +290,7 @@
 bool OCGs::allOff( Array *ocgArray )
 {
   for (int i = 0; i < ocgArray->getLength(); ++i) {
-    Object ocgItem;
-    ocgArray->getNF(i, &ocgItem);
+    Object ocgItem = ocgArray->getNF(i);
     if (ocgItem.isRef()) {
       OptionalContentGroup* oc = findOcgByRef( ocgItem.getRef() );      
       if ( oc && oc->getState() == OptionalContentGroup::On ) {
@@ -351,8 +304,7 @@
 bool OCGs::anyOn( Array *ocgArray )
 {
   for (int i = 0; i < ocgArray->getLength(); ++i) {
-    Object ocgItem;
-    ocgArray->getNF(i, &ocgItem);
+    Object ocgItem = ocgArray->getNF(i);
     if (ocgItem.isRef()) {
       OptionalContentGroup* oc = findOcgByRef( ocgItem.getRef() );      
       if ( oc && oc->getState() == OptionalContentGroup::On ) {
@@ -366,8 +318,7 @@
 bool OCGs::anyOff( Array *ocgArray )
 {
   for (int i = 0; i < ocgArray->getLength(); ++i) {
-    Object ocgItem;
-    ocgArray->getNF(i, &ocgItem);
+    Object ocgItem = ocgArray->getNF(i);
     if (ocgItem.isRef()) {
       OptionalContentGroup* oc = findOcgByRef( ocgItem.getRef() );      
       if ( oc && oc->getState() == OptionalContentGroup::Off ) {
@@ -382,42 +333,39 @@
 
 OptionalContentGroup::OptionalContentGroup(Dict *ocgDict) : m_name(NULL)
 {
-  Object obj1, obj2, obj3;
-  Object ocgName;
-  ocgDict->lookup("Name", &ocgName);
+  Object ocgName = ocgDict->lookup("Name");
   if (!ocgName.isString()) {
     error(errSyntaxWarning, -1, "Expected the name of the OCG, but wasn't able to find it, or it isn't a String");
   } else {
     m_name = new GooString( ocgName.getString() );
   }
-  ocgName.free();
 
   viewState = printState = ocUsageUnset;
-  if (ocgDict->lookup("Usage", &obj1)->isDict()) {
-    if (obj1.dictLookup("View", &obj2)->isDict()) {
-      if (obj2.dictLookup("ViewState", &obj3)->isName()) {
+  Object obj1 = ocgDict->lookup("Usage");
+  if (obj1.isDict()) {
+    Object obj2 = obj1.dictLookup("View");
+    if (obj2.isDict()) {
+      Object obj3 = obj2.dictLookup("ViewState");
+      if (obj3.isName()) {
 	if (obj3.isName("ON")) {
 	  viewState = ocUsageOn;
 	} else {
 	  viewState = ocUsageOff;
 	}
       }
-      obj3.free();
     }
-    obj2.free();
-    if (obj1.dictLookup("Print", &obj2)->isDict()) {
-      if (obj2.dictLookup("PrintState", &obj3)->isName()) {
+    obj2 = obj1.dictLookup("Print");
+    if (obj2.isDict()) {
+      Object obj3 = obj2.dictLookup("PrintState");
+      if (obj3.isName()) {
 	if (obj3.isName("ON")) {
 	  printState = ocUsageOn;
 	} else {
 	  printState = ocUsageOff;
 	}
       }
-      obj3.free();
     }
-    obj2.free();
   }
-  obj1.free();
 }
 
 OptionalContentGroup::OptionalContentGroup(GooString *label)
@@ -450,7 +398,6 @@
 
 OCDisplayNode *OCDisplayNode::parse(Object *obj, OCGs *oc,
 				    XRef *xref, int recursion) {
-  Object obj2, obj3;
   OptionalContentGroup *ocgA;
   OCDisplayNode *node, *child;
   int i;
@@ -464,25 +411,24 @@
       return new OCDisplayNode(ocgA);
     }
   }
-  obj->fetch(xref, &obj2);
+  Object obj2 = obj->fetch(xref);
   if (!obj2.isArray()) {
-    obj2.free();
     return NULL;
   }
   i = 0;
   if (obj2.arrayGetLength() >= 1) {
-    if (obj2.arrayGet(0, &obj3)->isString()) {
+    Object obj3 = obj2.arrayGet(0);
+    if (obj3.isString()) {
       node = new OCDisplayNode(obj3.getString());
       i = 1;
     } else {
       node = new OCDisplayNode();
     }
-    obj3.free();
   } else {
     node = new OCDisplayNode();
   }
   for (; i < obj2.arrayGetLength(); ++i) {
-    obj2.arrayGetNF(i, &obj3);
+    Object obj3 = obj2.arrayGetNF(i);
     if ((child = OCDisplayNode::parse(&obj3, oc, xref, recursion + 1))) {
       if (!child->ocg && !child->name && node->getNumChildren() > 0) {
 	node->getChild(node->getNumChildren() - 1)->addChildren(child->takeChildren());
@@ -491,9 +437,7 @@
 	node->addChild(child);
       }
     }
-    obj3.free();
   }
-  obj2.free();
   return node;
 }
 
diff --git a/poppler/Outline.cc b/poppler/Outline.cc
index bf46be2..8d539ca 100644
--- a/poppler/Outline.cc
+++ b/poppler/Outline.cc
@@ -14,7 +14,7 @@
 // under GPL version 2 or later
 //
 // Copyright (C) 2005 Marco Pesenti Gritti <mpg@redhat.com>
-// Copyright (C) 2008, 2016 Albert Astals Cid <aacid@kde.org>
+// 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>
 //
@@ -41,15 +41,12 @@
 //------------------------------------------------------------------------
 
 Outline::Outline(Object *outlineObj, XRef *xref) {
-  Object first, last;
-
-  items = NULL;
+  items = nullptr;
   if (!outlineObj->isDict()) {
     return;
   }
-  items = OutlineItem::readItemList(outlineObj->dictLookupNF("First", &first), xref);
-  first.free();
-  last.free();
+  Object first = outlineObj->dictLookupNF("First");
+  items = OutlineItem::readItemList(&first, xref);
 }
 
 Outline::~Outline() {
@@ -62,42 +59,41 @@
 
 OutlineItem::OutlineItem(Dict *dict, XRef *xrefA) {
   Object obj1;
-  GooString *s;
 
   xref = xrefA;
   title = NULL;
   action = NULL;
   kids = NULL;
 
-  if (dict->lookup("Title", &obj1)->isString()) {
-    s = obj1.getString();
+
+  if (obj1.isString()) {
+    GooString *s = obj1.getString();
     titleLen = TextStringToUCS4(s, &title);
   } else {
     titleLen = 0;
   }
-  obj1.free();
 
-  if (!dict->lookup("Dest", &obj1)->isNull()) {
+  obj1 = dict->lookup("Dest");
+  if (!obj1.isNull()) {
     action = LinkAction::parseDest(&obj1);
   } else {
-      obj1.free();
-    if (!dict->lookup("A", &obj1)->isNull()) {
-        action = LinkAction::parseAction(&obj1);
+    obj1 = dict->lookup("A");
+    if (!obj1.isNull()) {
+      action = LinkAction::parseAction(&obj1);
+    }
   }
-  }
-  obj1.free();
 
-  dict->lookupNF("First", &firstRef);
-  dict->lookupNF("Last", &lastRef);
-  dict->lookupNF("Next", &nextRef);
+  firstRef = dict->lookupNF("First");
+  lastRef = dict->lookupNF("Last");
+  nextRef = dict->lookupNF("Next");
 
   startsOpen = gFalse;
-  if (dict->lookup("Count", &obj1)->isInt()) {
+  obj1 = dict->lookup("Count");
+  if (obj1.isInt()) {
     if (obj1.getInt() > 0) {
       startsOpen = gTrue;
     }
   }
-  obj1.free();
 }
 
 OutlineItem::~OutlineItem() {
@@ -108,16 +104,12 @@
   if (action) {
     delete action;
   }
-  firstRef.free();
-  lastRef.free();
-  nextRef.free();
 }
 
 GooList *OutlineItem::readItemList(Object *firstItemRef, XRef *xrefA) {
   GooList *items;
   char* alreadyRead;
   OutlineItem *item;
-  Object obj;
   Object *p;
 
   items = new GooList();
@@ -130,13 +122,12 @@
 	 (p->getRefNum() >= 0) && 
          (p->getRefNum() < xrefA->getNumObjects()) && 
          !alreadyRead[p->getRefNum()]) {
-    if (!p->fetch(xrefA, &obj)->isDict()) {
-      obj.free();
+    Object obj = p->fetch(xrefA);
+    if (!obj.isDict()) {
       break;
     }
     alreadyRead[p->getRefNum()] = 1;
     item = new OutlineItem(obj.getDict(), xrefA);
-    obj.free();
     items->append(item);
     p = &item->nextRef;
   }
diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc
index ec5c700..35b3bc0 100644
--- a/poppler/PDFDoc.cc
+++ b/poppler/PDFDoc.cc
@@ -132,7 +132,6 @@
 
 PDFDoc::PDFDoc(GooString *fileNameA, GooString *ownerPassword,
 	       GooString *userPassword, void *guiDataA) {
-  Object obj;
 #ifdef _WIN32
   int n, i;
 #endif
@@ -163,8 +162,7 @@
   }
 
   // create stream
-  obj.initNull();
-  str = new FileStream(file, 0, gFalse, file->size(), &obj);
+  str = new FileStream(file, 0, gFalse, file->size(), Object(objNull));
 
   ok = setup(ownerPassword, userPassword);
 }
@@ -419,11 +417,10 @@
 }
 
 GBool PDFDoc::checkEncryption(GooString *ownerPassword, GooString *userPassword) {
-  Object encrypt;
   GBool encrypted;
   GBool ret;
 
-  xref->getTrailerDict()->dictLookup("Encrypt", &encrypt);
+  Object encrypt = xref->getTrailerDict()->dictLookup("Encrypt");
   if ((encrypted = encrypt.isDict())) {
     if ((secHdlr = SecurityHandler::make(this, &encrypt))) {
       if (secHdlr->isUnencrypted()) {
@@ -451,7 +448,6 @@
     // document is not encrypted
     ret = gTrue;
   }
-  encrypt.free();
   return ret;
 }
 
@@ -565,7 +561,6 @@
     return gFalse;
   }
   for (int page = 1; page <= linearization->getNumPages(); page++) {
-    Object obj;
     Ref pageRef;
 
     pageRef.num = hints->getPageObjectNum(page);
@@ -581,13 +576,11 @@
     }
 
     pageRef.gen = xref->getEntry(pageRef.num)->gen;
-    xref->fetch(pageRef.num, pageRef.gen, &obj);
+    Object obj = xref->fetch(pageRef.num, pageRef.gen);
     if (!obj.isDict("Page")) {
-      obj.free();
       linearizationState = 2;
       return gFalse;
     }
-    obj.free();
   }
   linearizationState = 1;
   return gTrue;
@@ -607,10 +600,8 @@
 
 void PDFDoc::setDocInfoModified(Object *infoObj)
 {
-  Object infoObjRef;
-  getDocInfoNF(&infoObjRef);
+  Object infoObjRef = getDocInfoNF();
   xref->setModifiedObject(infoObj, infoObjRef.getRef());
-  infoObjRef.free();
 }
 
 void PDFDoc::setDocInfoStringEntry(const char *key, GooString *value)
@@ -620,25 +611,19 @@
     delete value;
   }
 
-  Object infoObj;
-  getDocInfo(&infoObj);
-
+  Object infoObj = getDocInfo();
   if (infoObj.isNull() && removeEntry) {
     // No info dictionary, so no entry to remove.
     return;
   }
 
-  createDocInfoIfNoneExists(&infoObj);
-
-  Object gooStrObj;
+  infoObj = createDocInfoIfNoneExists();
   if (removeEntry) {
-    gooStrObj.initNull();
+    infoObj.dictSet(key, Object(objNull));
   } else {
-    gooStrObj.initString(value);
+    infoObj.dictSet(key, Object(value));
   }
 
-  // gooStrObj is set to value or null by now. The latter will cause a removal.
-  infoObj.dictSet(key, &gooStrObj);
 
   if (infoObj.dictGetLength() == 0) {
     // Info dictionary is empty. Remove it altogether.
@@ -646,19 +631,15 @@
   } else {
     setDocInfoModified(&infoObj);
   }
-
-  infoObj.free();
 }
 
 GooString *PDFDoc::getDocInfoStringEntry(const char *key) {
-  Object infoObj;
-  getDocInfo(&infoObj);
+  Object infoObj = getDocInfo();
   if (!infoObj.isDict()) {
       return NULL;
   }
 
-  Object entryObj;
-  infoObj.dictLookup(key, &entryObj);
+  Object entryObj = infoObj.dictLookup(key);
 
   GooString *result;
 
@@ -668,9 +649,6 @@
     result = NULL;
   }
 
-  entryObj.free();
-  infoObj.free();
-
   return result;
 }
 
@@ -696,45 +674,35 @@
 }
 
 GBool PDFDoc::getID(GooString *permanent_id, GooString *update_id) {
-  Object obj;
-  xref->getTrailerDict()->dictLookup ("ID", &obj);
+  Object obj = xref->getTrailerDict()->dictLookup ("ID");
 
   if (obj.isArray() && obj.arrayGetLength() == 2) {
-    Object obj2;
-
     if (permanent_id) {
-      if (obj.arrayGet(0, &obj2)->isString()) {
+      Object obj2 = obj.arrayGet(0);
+      if (obj2.isString()) {
         if (!get_id (obj2.getString(), permanent_id)) {
-	  obj2.free();
 	  return gFalse;
 	}
       } else {
         error(errSyntaxError, -1, "Invalid permanent ID");
-	obj2.free();
 	return gFalse;
       }
-      obj2.free();
     }
 
     if (update_id) {
-      if (obj.arrayGet(1, &obj2)->isString()) {
+      Object obj2 = obj.arrayGet(1);
+      if (obj2.isString()) {
         if (!get_id (obj2.getString(), update_id)) {
-	  obj2.free();
 	  return gFalse;
 	}
       } else {
         error(errSyntaxError, -1, "Invalid update ID");
-	obj2.free();
 	return gFalse;
       }
-      obj2.free();
     }
 
-    obj.free();
-
     return gTrue;
   }
-  obj.free();
 
   return gFalse;
 }
@@ -777,8 +745,7 @@
     getCatalog()->getPage(pageNo)->getMediaBox(),
     cropBox);
   Ref *refPage = getCatalog()->getPageRef(pageNo);
-  Object page;
-  getXRef()->fetch(refPage->num, refPage->gen, &page);
+  Object page = getXRef()->fetch(refPage->num, refPage->gen);
 
   if (!(f = fopen(name->getCString(), "wb"))) {
     error(errIO, -1, "Couldn't open file '{0:t}'", name);
@@ -801,55 +768,48 @@
   writeHeader(outStr, getPDFMajorVersion(), getPDFMinorVersion());
 
   // get and mark info dict
-  Object infoObj;
-  getXRef()->getDocInfo(&infoObj);
+  Object infoObj = getXRef()->getDocInfo();
   if (infoObj.isDict()) {
     Dict *infoDict = infoObj.getDict();
     markPageObjects(infoDict, yRef, countRef, 0, refPage->num, rootNum + 2);
     if (trailerObj->isDict()) {
       Dict *trailerDict = trailerObj->getDict();
-      Object ref;
-      trailerDict->lookupNF("Info", &ref);
+      Object ref = trailerDict->lookupNF("Info");
       if (ref.isRef()) {
         yRef->add(ref.getRef().num, ref.getRef().gen, 0, gTrue);
         if (getXRef()->getEntry(ref.getRef().num)->type == xrefEntryCompressed) {
           yRef->getEntry(ref.getRef().num)->type = xrefEntryCompressed;
         }
       }
-      ref.free();
     }
   }
-  infoObj.free();
   
   // get and mark output intents etc.
-  Object catObj, pagesObj, resourcesObj, annotsObj, afObj;
-  getXRef()->getCatalog(&catObj);
+  Object catObj = getXRef()->getCatalog();
   Dict *catDict = catObj.getDict();
-  catDict->lookup("Pages", &pagesObj);
-  catDict->lookupNF("AcroForm", &afObj);
+  Object pagesObj = catDict->lookup("Pages");
+  Object afObj = catDict->lookupNF("AcroForm");
   if (!afObj.isNull()) {
     markAcroForm(&afObj, yRef, countRef, 0, refPage->num, rootNum + 2);
-    afObj.free();
   }
   Dict *pagesDict = pagesObj.getDict();
-  pagesDict->lookup("Resources", &resourcesObj);
+  Object resourcesObj = pagesDict->lookup("Resources");
   if (resourcesObj.isDict())
     markPageObjects(resourcesObj.getDict(), yRef, countRef, 0, refPage->num, rootNum + 2);
   markPageObjects(catDict, yRef, countRef, 0, refPage->num, rootNum + 2);
 
   Dict *pageDict = page.getDict();
   if (resourcesObj.isNull() && !pageDict->hasKey("Resources")) {
-    Dict *resourceDict = getCatalog()->getPage(pageNo)->getResourceDict();
-    if (resourceDict != NULL) {
-      resourcesObj.initDict(resourceDict);
+    Object *resourceDictObject = getCatalog()->getPage(pageNo)->getResourceDictObject();
+    if (resourceDictObject->isDict()) {
+      resourcesObj = resourceDictObject->copy();
       markPageObjects(resourcesObj.getDict(), yRef, countRef, 0, refPage->num, rootNum + 2);
     }
   }
   markPageObjects(pageDict, yRef, countRef, 0, refPage->num, rootNum + 2);
-  pageDict->lookupNF("Annots", &annotsObj);
+  Object annotsObj = pageDict->lookupNF("Annots");
   if (!annotsObj.isNull()) {
     markAnnotations(&annotsObj, yRef, countRef, 0, refPage->num, rootNum + 2);
-    annotsObj.free();
   }
   yRef->markUnencrypted();
   writePageObjects(outStr, yRef, 0);
@@ -864,14 +824,11 @@
       strcmp(key, "Pages") != 0) 
     {
       if (j > 0) outStr->printf(" ");
-      Object value; catDict->getValNF(j, &value);
+      Object value = catDict->getValNF(j);
       outStr->printf("/%s ", key);
       writeObject(&value, outStr, getXRef(), 0, NULL, cryptRC4, 0, 0, 0);
-      value.free();
     }
   }
-  catObj.free();
-  pagesObj.free();
   outStr->printf(">>\nendobj\n");
 
   yRef->add(rootNum + 1,0,outStr->getPos(),gTrue);
@@ -880,7 +837,6 @@
   if (resourcesObj.isDict()) {
     outStr->printf("/Resources ");
     writeObject(&resourcesObj, outStr, getXRef(), 0, NULL, cryptRC4, 0, 0, 0);
-    resourcesObj.free();
   }
   outStr->printf(">>\n");
   outStr->printf("endobj\n");
@@ -891,27 +847,24 @@
   for (int n = 0; n < pageDict->getLength(); n++) {
     if (n > 0) outStr->printf(" ");
     const char *key = pageDict->getKey(n);
-    Object value; pageDict->getValNF(n, &value);
+    Object value = pageDict->getValNF(n);
     if (strcmp(key, "Parent") == 0) {
       outStr->printf("/Parent %d 0 R", rootNum + 1);
     } else {
       outStr->printf("/%s ", key);
       writeObject(&value, outStr, getXRef(), 0, NULL, cryptRC4, 0, 0, 0);
     }
-    value.free();
   }
   outStr->printf(" >>\nendobj\n");
-  page.free();
 
   Goffset uxrefOffset = outStr->getPos();
   Ref ref;
   ref.num = rootNum;
   ref.gen = 0;
-  Dict *trailerDict = createTrailerDict(rootNum + 3, gFalse, 0, &ref, getXRef(),
+  Object trailerDict = createTrailerDict(rootNum + 3, gFalse, 0, &ref, getXRef(),
                                         name->getCString(), uxrefOffset);
-  writeXRefTableTrailer(trailerDict, yRef, gFalse /* do not write unnecessary entries */,
+  writeXRefTableTrailer(std::move(trailerDict), yRef, gFalse /* do not write unnecessary entries */,
                         uxrefOffset, outStr, getXRef());
-  delete trailerDict;
 
   outStr->close();
   fclose(f);
@@ -1015,13 +968,11 @@
       ref.num = i;
       ref.gen = xref->getEntry(i)->type == xrefEntryCompressed ? 0 : xref->getEntry(i)->gen;
       if (xref->getEntry(i)->type != xrefEntryFree) {
-        Object obj1;
-        xref->fetch(ref.num, ref.gen, &obj1, 1);
+        Object obj1 = xref->fetch(ref.num, ref.gen, 1);
         Goffset offset = writeObjectHeader(&ref, outStr);
         writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen);
         writeObjectFooter(outStr);
         uxref->add(ref.num, ref.gen, offset, gTrue);
-        obj1.free();
       } else {
         uxref->add(ref.num, ref.gen, 0, gFalse);
       }
@@ -1052,14 +1003,13 @@
     uxref->add(uxrefStreamRef.num, uxrefStreamRef.gen, uxrefOffset, gTrue);
   }
 
-  Dict *trailerDict = createTrailerDict(numobjects, gTrue, getStartXRef(), &rootRef, getXRef(), fileNameA, uxrefOffset);
+  Object trailerDict = createTrailerDict(numobjects, gTrue, getStartXRef(), &rootRef, getXRef(), fileNameA, uxrefOffset);
   if (xRefStream) {
-    writeXRefStreamTrailer(trailerDict, uxref, &uxrefStreamRef, uxrefOffset, outStr, getXRef());
+    writeXRefStreamTrailer(std::move(trailerDict), uxref, &uxrefStreamRef, uxrefOffset, outStr, getXRef());
   } else {
-    writeXRefTableTrailer(trailerDict, uxref, gFalse, uxrefOffset, outStr, getXRef());
+    writeXRefTableTrailer(std::move(trailerDict), uxref, gFalse, uxrefOffset, outStr, getXRef());
   }
 
-  delete trailerDict;
   delete uxref;
 }
 
@@ -1079,7 +1029,6 @@
   uxref->add(0, 65535, 0, gFalse);
   xref->lock();
   for(int i=0; i<xref->getNumObjects(); i++) {
-    Object obj1;
     Ref ref;
     XRefEntryType type = xref->getEntry(i)->type;
     if (type == xrefEntryFree) {
@@ -1097,7 +1046,7 @@
     } else if (type == xrefEntryUncompressed){ 
       ref.num = i;
       ref.gen = xref->getEntry(i)->gen;
-      xref->fetch(ref.num, ref.gen, &obj1, 1);
+      Object obj1 = xref->fetch(ref.num, ref.gen, 1);
       Goffset offset = writeObjectHeader(&ref, outStr);
       // Write unencrypted objects in unencrypted form
       if (xref->getEntry(i)->getFlag(XRefEntry::Unencrypted)) {
@@ -1107,16 +1056,14 @@
       }
       writeObjectFooter(outStr);
       uxref->add(ref.num, ref.gen, offset, gTrue);
-      obj1.free();
     } else if (type == xrefEntryCompressed) {
       ref.num = i;
       ref.gen = 0; //compressed entries have gen == 0
-      xref->fetch(ref.num, ref.gen, &obj1, 1);
+      Object obj1 = xref->fetch(ref.num, ref.gen, 1);
       Goffset offset = writeObjectHeader(&ref, outStr);
       writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen);
       writeObjectFooter(outStr);
       uxref->add(ref.num, ref.gen, offset, gTrue);
-      obj1.free();
     }
   }
   xref->unlock();
@@ -1143,15 +1090,14 @@
     alreadyWrittenDicts->insert(dict);
   }
 
-  Object obj1;
   outStr->printf("<<");
   for (int i=0; i<dict->getLength(); i++) {
     GooString keyName(dict->getKey(i));
     GooString *keyNameToPrint = keyName.sanitizedName(gFalse /* non ps mode */);
     outStr->printf("/%s ", keyNameToPrint->getCString());
     delete keyNameToPrint;
-    writeObject(dict->getValNF(i, &obj1), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen, alreadyWrittenDicts);
-    obj1.free();
+    Object obj1 = dict->getValNF(i);
+    writeObject(&obj1, outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen, alreadyWrittenDicts);
   }
   outStr->printf(">> ");
 
@@ -1172,8 +1118,7 @@
 
 void PDFDoc::writeRawStream (Stream* str, OutStream* outStr)
 {
-  Object obj1;
-  str->getDict()->lookup("Length", &obj1);
+  Object obj1 = str->getDict()->lookup("Length");
   if (!obj1.isInt() && !obj1.isInt64()) {
     error (errSyntaxError, -1, "PDFDoc::writeRawStream, no Length in stream dict");
     return;
@@ -1184,7 +1129,6 @@
     length = obj1.getInt();
   else
     length = obj1.getInt64();
-  obj1.free();
 
   outStr->printf("stream\r\n");
   str->unfilteredReset();
@@ -1206,8 +1150,7 @@
   // Encrypt string if encryption is enabled
   GooString *sEnc = NULL;
   if (fileKey) {
-    Object obj;
-    EncryptStream *enc = new EncryptStream(new MemStream(s->getCString(), 0, s->getLength(), obj.initNull()),
+    EncryptStream *enc = new EncryptStream(new MemStream(s->getCString(), 0, s->getLength(), Object(objNull)),
                                            fileKey, encAlgorithm, keyLength, objNum, objGen);
     sEnc = new GooString();
     int c;
@@ -1267,8 +1210,6 @@
                           CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen, std::set<Dict*> *alreadyWrittenDicts)
 {
   Array *array;
-  Object obj1;
-  Goffset tmp;
 
   switch (obj->getType()) {
     case objBool:
@@ -1305,8 +1246,8 @@
       array = obj->getArray();
       outStr->printf("[");
       for (int i=0; i<array->getLength(); i++) {
-        writeObject(array->getNF(i, &obj1), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen);
-        obj1.free();
+	Object obj1 = array->getNF(i);
+        writeObject(&obj1, outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen);
       }
       outStr->printf("] ");
       break;
@@ -1325,19 +1266,15 @@
           EncryptStream *encStream = NULL;
           GBool removeFilter = gTrue;
           if (stream->getKind() == strWeird && fileKey) {
-            Object filter;
-            stream->getDict()->lookup("Filter", &filter);
+            Object filter = stream->getDict()->lookup("Filter");
             if (!filter.isName("Crypt")) {
               if (filter.isArray()) {
                 for (int i = 0; i < filter.arrayGetLength(); i++) {
-                  Object filterEle;
-                  filter.arrayGet(i, &filterEle);
+                  Object filterEle = filter.arrayGet(i);
                   if (filterEle.isName("Crypt")) {
-                    filterEle.free();
                     removeFilter = gFalse;
                     break;
                   }
-                  filterEle.free();
                 }
                 if (removeFilter) {
                   encStream = new EncryptStream(stream, fileKey, encAlgorithm, keyLength, objNum, objGen);
@@ -1352,7 +1289,6 @@
             } else {
               removeFilter = gFalse;
             }
-            filter.free();
           } else if (fileKey != NULL) { // Encrypt stream
             encStream = new EncryptStream(stream, fileKey, encAlgorithm, keyLength, objNum, objGen);
             encStream->setAutoDelete(gFalse);
@@ -1361,12 +1297,11 @@
 
           stream->reset();
           //recalculate stream length
-          tmp = 0;
+          Goffset tmp = 0;
           for (int c=stream->getChar(); c!=EOF; c=stream->getChar()) {
             tmp++;
           }
-          obj1.initInt64(tmp);
-          stream->getDict()->set("Length", &obj1);
+          stream->getDict()->set("Length", Object(tmp));
 
           //Remove Stream encoding
           if (removeFilter) {
@@ -1377,7 +1312,6 @@
           writeDictionnary (stream->getDict(),outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen, alreadyWrittenDicts);
           writeStream (stream,outStr);
           delete encStream;
-          obj1.free();
         } else {
           //raw stream copy
           FilterStream *fs = dynamic_cast<FilterStream*>(stream);
@@ -1386,9 +1320,8 @@
             if (bs) {
               Goffset streamEnd;
                 if (xRef->getStreamEnd(bs->getStart(), &streamEnd)) {
-                  Object val;
-                  val.initInt64(streamEnd - bs->getStart());
-                  stream->getDict()->set("Length", &val);
+                  Goffset val = streamEnd - bs->getStart();
+                  stream->getDict()->set("Length", Object(val));
                 }
               }
           }
@@ -1423,14 +1356,11 @@
   outStr->printf("endobj\r\n");
 }
 
-Dict *PDFDoc::createTrailerDict(int uxrefSize, GBool incrUpdate, Goffset startxRef,
+Object PDFDoc::createTrailerDict(int uxrefSize, GBool incrUpdate, Goffset startxRef,
                                 Ref *root, XRef *xRef, const char *fileName, Goffset fileSize)
 {
   Dict *trailerDict = new Dict(xRef);
-  Object obj1;
-  obj1.initInt(uxrefSize);
-  trailerDict->set("Size", &obj1);
-  obj1.free();
+  trailerDict->set("Size", Object(uxrefSize));
 
   //build a new ID, as recommended in the reference, uses:
   // - current time
@@ -1449,105 +1379,90 @@
   message.append(buffer);
 
   //info dict -- only use text string
-  if (!xRef->getTrailerDict()->isNone() && xRef->getDocInfo(&obj1)->isDict()) {
-    for(int i=0; i<obj1.getDict()->getLength(); i++) {
-      Object obj2;
-      obj1.getDict()->getVal(i, &obj2);  
+  Object docInfo = xRef->getDocInfo();
+  if (!xRef->getTrailerDict()->isNone() && docInfo.isDict()) {
+    for(int i=0; i<docInfo.getDict()->getLength(); i++) {
+      Object obj2 = docInfo.getDict()->getVal(i);
       if (obj2.isString()) {
         message.append(obj2.getString());
       }
-      obj2.free();
     }
   }
-  obj1.free();
 
   GBool hasEncrypt = gFalse;
   if (!xRef->getTrailerDict()->isNone()) {
-    Object obj2;
-    xRef->getTrailerDict()->dictLookupNF("Encrypt", &obj2);
+    Object obj2 = xRef->getTrailerDict()->dictLookupNF("Encrypt");
     if (!obj2.isNull()) {
-      trailerDict->set("Encrypt", &obj2);
+      trailerDict->set("Encrypt", std::move(obj2));
       hasEncrypt = gTrue;
-      obj2.free();
     }
   }
 
   //calculate md5 digest
   Guchar digest[16];
   md5((Guchar*)message.getCString(), message.getLength(), digest);
-  obj1.initString(new GooString((const char*)digest, 16));
 
   //create ID array
-  Object obj2,obj3,obj5;
-  obj2.initArray(xRef);
-
   // In case of encrypted files, the ID must not be changed because it's used to calculate the key
   if (incrUpdate || hasEncrypt) {
-    Object obj4;
     //only update the second part of the array
-    xRef->getTrailerDict()->getDict()->lookup("ID", &obj4);
+    Object obj4  = xRef->getTrailerDict()->getDict()->lookup("ID");
     if (!obj4.isArray()) {
       error(errSyntaxWarning, -1, "PDFDoc::createTrailerDict original file's ID entry isn't an array. Trying to continue");
     } else {
+      Array *array = new Array(xRef);
       //Get the first part of the ID
-      obj4.arrayGet(0,&obj3); 
-
-      obj2.arrayAdd(&obj3); 
-      obj2.arrayAdd(&obj1);
-      trailerDict->set("ID", &obj2);
+      array->add(obj4.arrayGet(0));
+      array->add(Object(new GooString((const char*)digest, 16)));
+      trailerDict->set("ID", Object(array));
     }
-    obj4.free();
   } else {
     //new file => same values for the two identifiers
-    obj2.arrayAdd(&obj1);
-    obj1.initString(new GooString((const char*)digest, 16));
-    obj2.arrayAdd(&obj1);
-    trailerDict->set("ID", &obj2);
+    Array *array = new Array(xRef);
+    array->add(Object(new GooString((const char*)digest, 16)));
+    array->add(Object(new GooString((const char*)digest, 16)));
+    trailerDict->set("ID", Object(array));
   }
 
-  obj1.initRef(root->num, root->gen);
-  trailerDict->set("Root", &obj1);
+  trailerDict->set("Root", Object(root->num, root->gen));
 
   if (incrUpdate) { 
-    obj1.initInt64(startxRef);
-    trailerDict->set("Prev", &obj1);
+    trailerDict->set("Prev", Object(startxRef));
   }
   
   if (!xRef->getTrailerDict()->isNone()) {
-    xRef->getDocInfoNF(&obj5);
+    Object obj5 = xRef->getDocInfoNF();
     if (!obj5.isNull()) {
-      trailerDict->set("Info", &obj5);
+      trailerDict->set("Info", std::move(obj5));
     }
   }
 
-  return trailerDict;
+  return Object(trailerDict);
 }
 
-void PDFDoc::writeXRefTableTrailer(Dict *trailerDict, XRef *uxref, GBool writeAllEntries, Goffset uxrefOffset, OutStream* outStr, XRef *xRef)
+void PDFDoc::writeXRefTableTrailer(Object &&trailerDict, XRef *uxref, GBool writeAllEntries, Goffset uxrefOffset, OutStream* outStr, XRef *xRef)
 {
   uxref->writeTableToFile( outStr, writeAllEntries );
   outStr->printf( "trailer\r\n");
-  writeDictionnary(trailerDict, outStr, xRef, 0, NULL, cryptRC4, 0, 0, 0, nullptr);
+  writeDictionnary(trailerDict.getDict(), outStr, xRef, 0, NULL, cryptRC4, 0, 0, 0, nullptr);
   outStr->printf( "\r\nstartxref\r\n");
   outStr->printf( "%lli\r\n", uxrefOffset);
   outStr->printf( "%%%%EOF\r\n");
 }
 
-void PDFDoc::writeXRefStreamTrailer (Dict *trailerDict, XRef *uxref, Ref *uxrefStreamRef, Goffset uxrefOffset, OutStream* outStr, XRef *xRef)
+void PDFDoc::writeXRefStreamTrailer (Object &&trailerDict, XRef *uxref, Ref *uxrefStreamRef, Goffset uxrefOffset, OutStream* outStr, XRef *xRef)
 {
   GooString stmData;
 
   // Fill stmData and some trailerDict fields
-  uxref->writeStreamToBuffer(&stmData, trailerDict, xRef);
+  uxref->writeStreamToBuffer(&stmData, trailerDict.getDict(), xRef);
 
   // Create XRef stream object and write it
-  Object obj1;
-  MemStream *mStream = new MemStream( stmData.getCString(), 0,
-                                      stmData.getLength(), obj1.initDict(trailerDict) );
+  MemStream *mStream = new MemStream( stmData.getCString(), 0, stmData.getLength(), std::move(trailerDict) );
   writeObjectHeader(uxrefStreamRef, outStr);
-  writeObject(obj1.initStream(mStream), outStr, xRef, 0, NULL, cryptRC4, 0, 0, 0);
+  Object obj1(static_cast<Stream*>(mStream));
+  writeObject(&obj1, outStr, xRef, 0, NULL, cryptRC4, 0, 0, 0);
   writeObjectFooter(outStr);
-  obj1.free();
 
   outStr->printf( "startxref\r\n");
   outStr->printf( "%lli\r\n", uxrefOffset);
@@ -1569,10 +1484,9 @@
   Ref ref;
   ref.num = getXRef()->getRootNum();
   ref.gen = getXRef()->getRootGen();
-  Dict * trailerDict = createTrailerDict(uxrefSize, incrUpdate, getStartXRef(), &ref,
+  Object trailerDict = createTrailerDict(uxrefSize, incrUpdate, getStartXRef(), &ref,
                                          getXRef(), fileNameA, fileSize);
-  writeXRefTableTrailer(trailerDict, uxref, writeAllEntries, uxrefOffset, outStr, getXRef());
-  delete trailerDict;
+  writeXRefTableTrailer(std::move(trailerDict), uxref, writeAllEntries, uxrefOffset, outStr, getXRef());
 }
 
 void PDFDoc::writeHeader(OutStream *outStr, int major, int minor)
@@ -1601,16 +1515,14 @@
   for (int i=0; i<dict->getLength(); i++) {
     const char *key = dict->getKey(i);
     if (strcmp(key, "Annots") != 0) {
-      markObject(dict->getValNF(i, &obj1), xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts);
+      Object obj1 = dict->getValNF(i);
+      markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts);
     } else {
-      Object annotsObj;
-      dict->getValNF(i, &annotsObj);
+      Object annotsObj = dict->getValNF(i);
       if (!annotsObj.isNull()) {
         markAnnotations(&annotsObj, xRef, countRef, 0, oldRefNum, newRefNum, alreadyMarkedDicts);
-        annotsObj.free();
       }
     }
-    obj1.free();
   }
 
   if (deleteSet) {
@@ -1621,14 +1533,13 @@
 void PDFDoc::markObject (Object* obj, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum, std::set<Dict*> *alreadyMarkedDicts)
 {
   Array *array;
-  Object obj1;
 
   switch (obj->getType()) {
     case objArray:
       array = obj->getArray();
       for (int i=0; i<array->getLength(); i++) {
-        markObject(array->getNF(i, &obj1), xRef, countRef, numOffset, oldRefNum, newRefNum);
-        obj1.free();
+        Object obj1 = array->getNF(i);
+        markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum);
       }
       break;
     case objDict:
@@ -1661,10 +1572,8 @@
           if (entry->gen > 9)
             break;
         } 
-        Object obj1;
-        getXRef()->fetch(obj->getRef().num, obj->getRef().gen, &obj1);
+        Object obj1 = getXRef()->fetch(obj->getRef().num, obj->getRef().gen);
         markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum);
-        obj1.free();
       }
       break;
     default:
@@ -1677,8 +1586,7 @@
                              PDFRectangle *cropBox)
 {
   Ref *refPage = getCatalog()->getPageRef(pageNo);
-  Object page;
-  getXRef()->fetch(refPage->num, refPage->gen, &page);
+  Object page = getXRef()->fetch(refPage->num, refPage->gen);
   Dict *pageDict = page.getDict();
   pageDict->remove("MediaBoxssdf");
   pageDict->remove("MediaBox");
@@ -1687,48 +1595,27 @@
   pageDict->remove("BleedBox");
   pageDict->remove("TrimBox");
   pageDict->remove("Rotate");
-  Object mediaBoxObj;
-  mediaBoxObj.initArray(getXRef());
-  Object murx;
-  murx.initReal(mediaBox->x1);
-  Object mury;
-  mury.initReal(mediaBox->y1);
-  Object mllx;
-  mllx.initReal(mediaBox->x2);
-  Object mlly;
-  mlly.initReal(mediaBox->y2);
-  mediaBoxObj.arrayAdd(&murx);
-  mediaBoxObj.arrayAdd(&mury);
-  mediaBoxObj.arrayAdd(&mllx);
-  mediaBoxObj.arrayAdd(&mlly);
-  pageDict->add(copyString("MediaBox"), &mediaBoxObj);
+  Array *mediaBoxArray = new Array(getXRef());
+  mediaBoxArray->add(Object(mediaBox->x1));
+  mediaBoxArray->add(Object(mediaBox->y1));
+  mediaBoxArray->add(Object(mediaBox->x2));
+  mediaBoxArray->add(Object(mediaBox->y2));
+  Object mediaBoxObject(mediaBoxArray);
+  Object trimBoxObject = mediaBoxObject.copy();
+  pageDict->add(copyString("MediaBox"), std::move(mediaBoxObject));
   if (cropBox != NULL) {
-    Object cropBoxObj;
-    cropBoxObj.initArray(getXRef());
-    Object curx;
-    curx.initReal(cropBox->x1);
-    Object cury;
-    cury.initReal(cropBox->y1);
-    Object cllx;
-    cllx.initReal(cropBox->x2);
-    Object clly;
-    clly.initReal(cropBox->y2);
-    cropBoxObj.arrayAdd(&curx);
-    cropBoxObj.arrayAdd(&cury);
-    cropBoxObj.arrayAdd(&cllx);
-    cropBoxObj.arrayAdd(&clly);
-    pageDict->add(copyString("CropBox"), &cropBoxObj);
-    cropBoxObj.getArray()->incRef();
-    pageDict->add(copyString("TrimBox"), &cropBoxObj);
-  } else {
-    mediaBoxObj.getArray()->incRef();
-    pageDict->add(copyString("TrimBox"), &mediaBoxObj);
+    Array *cropBoxArray = new Array(getXRef());
+    cropBoxArray->add(Object(cropBox->x1));
+    cropBoxArray->add(Object(cropBox->y1));
+    cropBoxArray->add(Object(cropBox->x2));
+    cropBoxArray->add(Object(cropBox->y2));
+    Object cropBoxObject(cropBoxArray);
+    trimBoxObject = cropBoxObject.copy();
+    pageDict->add(copyString("CropBox"), std::move(cropBoxObject));
   }
-  Object rotateObj;
-  rotateObj.initInt(rotate);
-  pageDict->add(copyString("Rotate"), &rotateObj);
+  pageDict->add(copyString("TrimBox"), std::move(trimBoxObject));
+  pageDict->add(copyString("Rotate"), Object(rotate));
   getXRef()->setModifiedObject(&page, *refPage);
-  page.free();
 }
 
 void PDFDoc::markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum, std::set<Dict*> *alreadyMarkedDicts)
@@ -1739,7 +1626,7 @@
 
   for (int n = 0; n < pageDict->getLength(); n++) {
     const char *key = pageDict->getKey(n);
-    Object value; pageDict->getValNF(n, &value);
+    Object value  = pageDict->getValNF(n);
     if (strcmp(key, "Parent") != 0 &&
 	      strcmp(key, "Pages") != 0 &&
 	      strcmp(key, "AcroForm") != 0 &&
@@ -1748,73 +1635,48 @@
         strcmp(key, "Root") != 0) {
       markObject(&value, xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts);
     }
-    value.free();
   }
 }
 
 GBool PDFDoc::markAnnotations(Object *annotsObj, XRef *xRef, XRef *countRef, Guint numOffset, int oldPageNum, int newPageNum, std::set<Dict*> *alreadyMarkedDicts) {
-  Object annots;
   GBool modified = gFalse;
-  annotsObj->fetch(getXRef(), &annots);
+  Object annots = annotsObj->fetch(getXRef());
   if (annots.isArray()) {
       Array *array = annots.getArray();
       for (int i=array->getLength() - 1; i >= 0; i--) {
-        Object obj1;
-        if (array->get(i, &obj1)->isDict()) {
-          Object type;
+        Object obj1 = array->get(i);
+        if (obj1.isDict()) {
           Dict *dict = obj1.getDict();
-          dict->lookup("Type", &type);
+          Object type = dict->lookup("Type");
           if (type.isName() && strcmp(type.getName(), "Annot") == 0) {
-            Object obj2;
-            if (dict->lookupNF("P", &obj2)->isRef()) {
+            Object obj2 = dict->lookupNF("P");
+            if (obj2.isRef()) {
               if (obj2.getRef().num == oldPageNum) {
-                Object obj3;
-                array->getNF(i, &obj3);
+                Object obj3 = array->getNF(i);
                 if (obj3.isRef()) {
-                  Object newRef;
-                  newRef.initRef(newPageNum, 0);
-                  dict->set("P", &newRef);
+                  dict->set("P", Object(newPageNum, 0));
                   getXRef()->setModifiedObject(&obj1, obj3.getRef());
                 }
-                obj3.free();
               } else if (obj2.getRef().num == newPageNum) {
-                obj1.free();
-                obj2.free();
-                type.free();
                 continue;
               } else {
-                Object page;
-                getXRef()->fetch(obj2.getRef().num, obj2.getRef().gen, &page);
+                Object page  = getXRef()->fetch(obj2.getRef().num, obj2.getRef().gen);
                 if (page.isDict()) {
-                  Object pagetype;
                   Dict *dict = page.getDict();
-                  dict->lookup("Type", &pagetype);
+                  Object pagetype = dict->lookup("Type");
                   if (!pagetype.isName() || strcmp(pagetype.getName(), "Page") != 0) {
-                    obj1.free();
-                    obj2.free();
-                    type.free();
-                    page.free();
-                    pagetype.free();
                     continue;
                   }
-                  pagetype.free();
                 }
-                page.free();
-                obj1.free();
-                obj2.free();
-                type.free();
                 array->remove(i);
                 modified = gTrue;
                 continue;
               }
             }
-            obj2.free();
           }
-          type.free();
           markPageObjects(dict, xRef, countRef, numOffset, oldPageNum, newPageNum, alreadyMarkedDicts);
         }
-        obj1.free();
-        array->getNF(i, &obj1);
+        obj1 = array->getNF(i);
         if (obj1.isRef()) {
           if (obj1.getRef().num + (int) numOffset >= xRef->getNumObjects() || xRef->getEntry(obj1.getRef().num + numOffset)->type == xrefEntryFree) {
             if (getXRef()->getEntry(obj1.getRef().num)->type == xrefEntryFree) {
@@ -1834,7 +1696,6 @@
             entry->gen++;
           } 
         }
-        obj1.free();
       }
   }
   if (annotsObj->isRef()) {
@@ -1857,25 +1718,21 @@
     } 
     getXRef()->setModifiedObject(&annots, annotsObj->getRef());
   }
-  annots.free();
   return modified;
 }
 
 void PDFDoc::markAcroForm(Object *afObj, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum) {
-  Object acroform;
   GBool modified = gFalse;
-  afObj->fetch(getXRef(), &acroform);
+  Object acroform = afObj->fetch(getXRef());
   if (acroform.isDict()) {
       Dict *dict = acroform.getDict();
       for (int i=0; i < dict->getLength(); i++) {
         if (strcmp(dict->getKey(i), "Fields") == 0) {
-          Object fields;
-          modified = markAnnotations(dict->getValNF(i, &fields), xRef, countRef, numOffset, oldRefNum, newRefNum);
-          fields.free();
+          Object fields = dict->getValNF(i);
+          modified = markAnnotations(&fields, xRef, countRef, numOffset, oldRefNum, newRefNum);
         } else {
-          Object obj;
-          markObject(dict->getValNF(i, &obj), xRef, countRef, numOffset, oldRefNum, newRefNum);
-          obj.free();
+          Object obj = dict->getValNF(i);
+          markObject(&obj, xRef, countRef, numOffset, oldRefNum, newRefNum);
         }
       }
   }
@@ -1901,7 +1758,6 @@
       getXRef()->setModifiedObject(&acroform, afObj->getRef());
     }
   }
-  acroform.free();
   return;
 }
 
@@ -1915,12 +1771,11 @@
 
   for (int n = numOffset; n < xRef->getNumObjects(); n++) {
     if (xRef->getEntry(n)->type != xrefEntryFree) {
-      Object obj;
       Ref ref;
       ref.num = n;
       ref.gen = xRef->getEntry(n)->gen;
       objectsCount++;
-      getXRef()->fetch(ref.num - numOffset, ref.gen, &obj);
+      Object obj = getXRef()->fetch(ref.num - numOffset, ref.gen);
       Goffset offset = writeObjectHeader(&ref, outStr);
       if (combine) {
         writeObject(&obj, outStr, getXRef(), numOffset, NULL, cryptRC4, 0, 0, 0);
@@ -1931,7 +1786,6 @@
       }
       writeObjectFooter(outStr);
       xRef->add(ref.num, ref.gen, offset, gTrue);
-      obj.free();
     }
   }
   return objectsCount;
@@ -2068,10 +1922,7 @@
 
 Page *PDFDoc::parsePage(int page)
 {
-  Page *p = NULL;
-  Object obj;
   Ref pageRef;
-  Dict *pageDict;
 
   pageRef.num = getHints()->getPageObjectNum(page);
   if (!pageRef.num) {
@@ -2086,19 +1937,15 @@
   }
 
   pageRef.gen = xref->getEntry(pageRef.num)->gen;
-  xref->fetch(pageRef.num, pageRef.gen, &obj);
+  Object obj = xref->fetch(pageRef.num, pageRef.gen);
   if (!obj.isDict("Page")) {
-    obj.free();
     error(errSyntaxWarning, -1, "Object ({0:d} {1:d}) is not a pageDict", pageRef.num, pageRef.gen);
     return NULL;
   }
-  pageDict = obj.getDict();
+  Dict *pageDict = obj.getDict();
 
-  p = new Page(this, page, pageDict, pageRef,
+  return new Page(this, page, &obj, pageRef,
                new PageAttrs(NULL, pageDict), catalog->getForm());
-  obj.free();
-
-  return p;
 }
 
 Page *PDFDoc::getPage(int page)
diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h
index c5621ec..83a2e97 100644
--- a/poppler/PDFDoc.h
+++ b/poppler/PDFDoc.h
@@ -229,12 +229,12 @@
   GBool isLinearized(GBool tryingToReconstruct = gFalse);
 
   // Return the document's Info dictionary (if any).
-  Object *getDocInfo(Object *obj) { return xref->getDocInfo(obj); }
-  Object *getDocInfoNF(Object *obj) { return xref->getDocInfoNF(obj); }
+  Object getDocInfo() { return xref->getDocInfo(); }
+  Object getDocInfoNF() { return xref->getDocInfoNF(); }
 
   // Create and return the document's Info dictionary if none exists.
   // Otherwise return the existing one.
-  Object *createDocInfoIfNoneExists(Object *obj) { return xref->createDocInfoIfNoneExists(obj); }
+  Object createDocInfoIfNoneExists() { return xref->createDocInfoIfNoneExists(); }
 
   // Remove the document's Info dictionary and update the trailer dictionary.
   void removeDocInfo() { xref->removeDocInfo(); }
@@ -301,12 +301,11 @@
                            CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen, std::set<Dict*> *alreadyWrittenDicts = nullptr);
   static void writeHeader(OutStream *outStr, int major, int minor);
 
-  // Ownership goes to the caller
-  static Dict *createTrailerDict (int uxrefSize, GBool incrUpdate, Goffset startxRef,
+  static Object createTrailerDict (int uxrefSize, GBool incrUpdate, Goffset startxRef,
                                   Ref *root, XRef *xRef, const char *fileName, Goffset fileSize);
-  static void writeXRefTableTrailer (Dict *trailerDict, XRef *uxref, GBool writeAllEntries,
+  static void writeXRefTableTrailer (Object &&trailerDict, XRef *uxref, GBool writeAllEntries,
                                      Goffset uxrefOffset, OutStream* outStr, XRef *xRef);
-  static void writeXRefStreamTrailer (Dict *trailerDict, XRef *uxref, Ref *uxrefStreamRef,
+  static void writeXRefStreamTrailer (Object &&trailerDict, XRef *uxref, Ref *uxrefStreamRef,
                                       Goffset uxrefOffset, OutStream* outStr, XRef *xRef);
 
 private:
diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc
index 0ff0bbb..b2d6d3a 100644
--- a/poppler/PSOutputDev.cc
+++ b/poppler/PSOutputDev.cc
@@ -15,7 +15,7 @@
 //
 // Copyright (C) 2005 Martin Kretzschmar <martink@gnome.org>
 // Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
-// Copyright (C) 2006-2009, 2011-2013, 2015, 2016 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006-2009, 2011-2013, 2015-2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2006 Jeff Muizelaar <jeff@infidigm.net>
 // Copyright (C) 2007, 2008 Brad Hards <bradh@kde.org>
 // Copyright (C) 2008, 2009 Koji Otani <sho@bbr.jp>
@@ -1533,7 +1533,6 @@
 void PSOutputDev::writeHeader(const std::vector<int> &pages,
 			      PDFRectangle *mediaBox, PDFRectangle *cropBox,
 			      int pageRotate, char *psTitle) {
-  Object info, obj1;
   PSOutPaperSize *size;
   double x1, y1, x2, y2;
   int i;
@@ -1550,13 +1549,14 @@
     break;
   }
   writePSFmt("%Produced by poppler pdftops version: {0:s} (http://poppler.freedesktop.org)\n", PACKAGE_VERSION);
-  xref->getDocInfo(&info);
-  if (info.isDict() && info.dictLookup("Creator", &obj1)->isString()) {
-    writePS("%%Creator: ");
-    writePSTextLine(obj1.getString());
+  Object info = xref->getDocInfo();
+  if (info.isDict()) {
+    Object obj1 = info.dictLookup("Creator");
+    if (obj1.isString()) {
+        writePS("%%Creator: ");
+        writePSTextLine(obj1.getString());
+    }
   }
-  obj1.free();
-  info.free();
   if(psTitle) {
     char *sanitizedTitle = strdup(psTitle);
     for (Guint i = 0; i < strlen(sanitizedTitle); ++i) {
@@ -1677,9 +1677,7 @@
   Dict *resDict;
   Annots *annots;
   Object *acroForm;
-  Object obj1, obj2, obj3;
   GooString *s;
-  int i;
 
   if (mode == psModeForm) {
     // swap the form and xpdf dicts
@@ -1698,30 +1696,30 @@
       setupResources(resDict);
     }
     annots = page->getAnnots();
-    for (i = 0; i < annots->getNumAnnots(); ++i) {
-      if (annots->getAnnot(i)->getAppearanceResDict(&obj1)->isDict()) {
+    for (int i = 0; i < annots->getNumAnnots(); ++i) {
+      Object obj1 = annots->getAnnot(i)->getAppearanceResDict();
+      if (obj1.isDict()) {
         setupResources(obj1.getDict());
       }
-      obj1.free();
     }
   }
   if ((acroForm = catalog->getAcroForm()) && acroForm->isDict()) {
-    if (acroForm->dictLookup("DR", &obj1)->isDict()) {
+    Object obj1 = acroForm->dictLookup("DR");
+    if (obj1.isDict()) {
       setupResources(obj1.getDict());
     }
-    obj1.free();
-    if (acroForm->dictLookup("Fields", &obj1)->isArray()) {
-      for (i = 0; i < obj1.arrayGetLength(); ++i) {
-	if (obj1.arrayGet(i, &obj2)->isDict()) {
-	  if (obj2.dictLookup("DR", &obj3)->isDict()) {
+    obj1 = acroForm->dictLookup("Fields");
+    if (obj1.isArray()) {
+      for (int i = 0; i < obj1.arrayGetLength(); ++i) {
+	Object obj2 = obj1.arrayGet(i);
+	if (obj2.isDict()) {
+	  Object obj3 = obj2.dictLookup("DR");
+	  if (obj3.isDict()) {
 	    setupResources(obj3.getDict());
 	  }
-	  obj3.free();
 	}
-	obj2.free();
       }
     }
-    obj1.free();
   }
   if (mode != psModeForm) {
     if (mode != psModeEPS && !manualCtrl) {
@@ -1795,24 +1793,22 @@
 }
 
 void PSOutputDev::setupResources(Dict *resDict) {
-  Object xObjDict, xObjRef, xObj, patDict, patRef, pat, resObj;
-  Ref ref0;
   GBool skip;
-  int i;
 
   setupFonts(resDict);
   setupImages(resDict);
   setupForms(resDict);
 
   //----- recursively scan XObjects
-  resDict->lookup("XObject", &xObjDict);
+  Object xObjDict = resDict->lookup("XObject");
   if (xObjDict.isDict()) {
-    for (i = 0; i < xObjDict.dictGetLength(); ++i) {
+    for (int i = 0; i < xObjDict.dictGetLength(); ++i) {
 
       // avoid infinite recursion on XObjects
       skip = gFalse;
-      if ((xObjDict.dictGetValNF(i, &xObjRef)->isRef())) {
-	ref0 = xObjRef.getRef();
+      Object xObjRef = xObjDict.dictGetValNF(i);
+      if (xObjRef.isRef()) {
+	Ref ref0 = xObjRef.getRef();
 	if (resourceIDs.find(ref0.num) != resourceIDs.end()) {
 	  skip = gTrue;
 	} else {
@@ -1822,32 +1818,28 @@
       if (!skip) {
 
 	// process the XObject's resource dictionary
-	xObjDict.dictGetVal(i, &xObj);
+	Object xObj = xObjDict.dictGetVal(i);
 	if (xObj.isStream()) {
-	  xObj.streamGetDict()->lookup("Resources", &resObj);
+	  Object resObj = xObj.streamGetDict()->lookup("Resources");
 	  if (resObj.isDict()) {
 	    setupResources(resObj.getDict());
 	  }
-	  resObj.free();
 	}
-	xObj.free();
       }
-
-      xObjRef.free();
     }
   }
-  xObjDict.free();
 
   //----- recursively scan Patterns
-  resDict->lookup("Pattern", &patDict);
+  Object patDict = resDict->lookup("Pattern");
   if (patDict.isDict()) {
     inType3Char = gTrue;
-    for (i = 0; i < patDict.dictGetLength(); ++i) {
+    for (int i = 0; i < patDict.dictGetLength(); ++i) {
 
       // avoid infinite recursion on Patterns
       skip = gFalse;
-      if ((patDict.dictGetValNF(i, &patRef)->isRef())) {
-	ref0 = patRef.getRef();
+      Object patRef = patDict.dictGetValNF(i);
+      if (patRef.isRef()) {
+	Ref ref0 = patRef.getRef();
 	if (resourceIDs.find(ref0.num) != resourceIDs.end()) {
 	  skip = gTrue;
 	} else {
@@ -1857,40 +1849,33 @@
       if (!skip) {
 
 	// process the Pattern's resource dictionary
-	patDict.dictGetVal(i, &pat);
+	Object pat = patDict.dictGetVal(i);
 	if (pat.isStream()) {
-	  pat.streamGetDict()->lookup("Resources", &resObj);
+	  Object resObj = pat.streamGetDict()->lookup("Resources");
 	  if (resObj.isDict()) {
 	    setupResources(resObj.getDict());
 	  }
-	  resObj.free();
 	}
-	pat.free();
       }
-
-      patRef.free();
     }
     inType3Char = gFalse;
   }
-  patDict.free();
 }
 
 void PSOutputDev::setupFonts(Dict *resDict) {
-  Object obj1, obj2;
   Ref r;
   GfxFontDict *gfxFontDict;
   GfxFont *font;
   int i;
 
-  gfxFontDict = NULL;
-  resDict->lookupNF("Font", &obj1);
+  gfxFontDict = nullptr;
+  Object obj1 = resDict->lookupNF("Font");
   if (obj1.isRef()) {
-    obj1.fetch(xref, &obj2);
+    Object obj2 = obj1.fetch(xref);
     if (obj2.isDict()) {
       r = obj1.getRef();
       gfxFontDict = new GfxFontDict(xref, &r, obj2.getDict());
     }
-    obj2.free();
   } else if (obj1.isDict()) {
     gfxFontDict = new GfxFontDict(xref, NULL, obj1.getDict());
   }
@@ -1902,7 +1887,6 @@
     }
     delete gfxFontDict;
   }
-  obj1.free();
 }
 
 void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
@@ -2136,14 +2120,12 @@
 
 void PSOutputDev::setupEmbeddedType1Font(Ref *id, GooString *psName) {
   static const char hexChar[17] = "0123456789abcdef";
-  Object refObj, strObj, obj1, obj2, obj3;
   Dict *dict;
   long length1, length2, length3;
-  int c;
+  int c, i;
   int start[4];
   GBool binMode;
   GBool writePadding = gTrue;
-  int i;
 
   // check if font is already embedded
   if (fontNames->lookupInt(psName)) {
@@ -2152,9 +2134,9 @@
   fontNames->add(psName->copy(), 1);
 
   // get the font stream and info
-  refObj.initRef(id->num, id->gen);
-  refObj.fetch(xref, &strObj);
-  refObj.free();
+  Object obj1, obj2, obj3;
+  Object refObj(id->num, id->gen);
+  Object strObj = refObj.fetch(xref);
   if (!strObj.isStream()) {
     error(errSyntaxError, -1, "Embedded font file object is not a stream");
     goto err1;
@@ -2164,23 +2146,17 @@
 	  "Embedded font stream is missing its dictionary");
     goto err1;
   }
-  dict->lookup("Length1", &obj1);
-  dict->lookup("Length2", &obj2);
-  dict->lookup("Length3", &obj3);
+  obj1 = dict->lookup("Length1");
+  obj2 = dict->lookup("Length2");
+  obj3 = dict->lookup("Length3");
   if (!obj1.isInt() || !obj2.isInt() || !obj3.isInt()) {
     error(errSyntaxError, -1,
 	  "Missing length fields in embedded font stream dictionary");
-    obj1.free();
-    obj2.free();
-    obj3.free();
     goto err1;
   }
   length1 = obj1.getInt();
   length2 = obj2.getInt();
   length3 = obj3.getInt();
-  obj1.free();
-  obj2.free();
-  obj3.free();
 
   // beginning comment
   writePSFmt("%%BeginResource: font {0:t}\n", psName);
@@ -2324,7 +2300,6 @@
  err1:
   if (strObj.isStream())
     strObj.streamClose();
-  strObj.free();
 }
 
 void PSOutputDev::setupExternalType1Font(GooString *fileName, GooString *psName) {
@@ -2796,7 +2771,6 @@
 				 Dict *parentResDict) {
   Dict *resDict;
   Dict *charProcs;
-  Object charProc;
   Gfx *gfx;
   PDFRectangle box;
   double *m;
@@ -2854,8 +2828,8 @@
       writePS("/");
       writePSName(charProcs->getKey(i));
       writePS(" {\n");
-      gfx->display(charProcs->getVal(i, &charProc));
-      charProc.free();
+      Object charProc = charProcs->getVal(i);
+      gfx->display(&charProc);
       if (t3String) {
 	if (t3Cacheable) {
 	  buf = GooString::format("{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g} setcachedevice\n",
@@ -2922,25 +2896,24 @@
 }
 
 void PSOutputDev::setupImages(Dict *resDict) {
-  Object xObjDict, xObj, xObjRef, subtypeObj, maskObj, maskRef;
   Ref imgID;
-  int i, j;
 
   if (!(mode == psModeForm || inType3Char || preloadImagesForms)) {
     return;
   }
 
   //----- recursively scan XObjects
-  resDict->lookup("XObject", &xObjDict);
+  Object xObjDict = resDict->lookup("XObject");
   if (xObjDict.isDict()) {
-    for (i = 0; i < xObjDict.dictGetLength(); ++i) {
-      xObjDict.dictGetValNF(i, &xObjRef);
-      xObjDict.dictGetVal(i, &xObj);
+    for (int i = 0; i < xObjDict.dictGetLength(); ++i) {
+      Object xObjRef = xObjDict.dictGetValNF(i);
+      Object xObj = xObjDict.dictGetVal(i);
       if (xObj.isStream()) {
-	xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
+	Object subtypeObj = xObj.streamGetDict()->lookup("Subtype");
 	if (subtypeObj.isName("Image")) {
 	  if (xObjRef.isRef()) {
 	    imgID = xObjRef.getRef();
+	    int j;
 	    for (j = 0; j < imgIDLen; ++j) {
 	      if (imgIDs[j].num == imgID.num && imgIDs[j].gen == imgID.gen) {
 		break;
@@ -2957,24 +2930,21 @@
 	      }
 	      imgIDs[imgIDLen++] = imgID;
 	      setupImage(imgID, xObj.getStream(), gFalse);
-	      if (level >= psLevel3 &&
-		  xObj.streamGetDict()->lookup("Mask", &maskObj)->isStream()) {
-		setupImage(imgID, maskObj.getStream(), gTrue);
+	      if (level >= psLevel3) {
+		Object maskObj = xObj.streamGetDict()->lookup("Mask");
+		if (maskObj.isStream()) {
+		  setupImage(imgID, maskObj.getStream(), gTrue);
+		}
 	      }
-	      maskObj.free();
 	    }
 	  } else {
 	    error(errSyntaxError, -1,
 		  "Image in resource dict is not an indirect reference");
 	  }
 	}
-	subtypeObj.free();
       }
-      xObj.free();
-      xObjRef.free();
     }
   }
-  xObjDict.free();
 }
 
 void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask) {
@@ -3146,20 +3116,17 @@
 }
 
 void PSOutputDev::setupForms(Dict *resDict) {
-  Object xObjDict, xObj, xObjRef, subtypeObj;
-  int i;
-
   if (!preloadImagesForms) {
     return;
   }
 
-  resDict->lookup("XObject", &xObjDict);
+  Object xObjDict = resDict->lookup("XObject");
   if (xObjDict.isDict()) {
-    for (i = 0; i < xObjDict.dictGetLength(); ++i) {
-      xObjDict.dictGetValNF(i, &xObjRef);
-      xObjDict.dictGetVal(i, &xObj);
+    for (int i = 0; i < xObjDict.dictGetLength(); ++i) {
+      Object xObjRef = xObjDict.dictGetValNF(i);
+      Object xObj = xObjDict.dictGetVal(i);
       if (xObj.isStream()) {
-	xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
+	Object subtypeObj = xObj.streamGetDict()->lookup("Subtype");
 	if (subtypeObj.isName("Form")) {
 	  if (xObjRef.isRef()) {
 	    setupForm(xObjRef.getRef(), &xObj);
@@ -3168,25 +3135,19 @@
 		  "Form in resource dict is not an indirect reference");
 	  }
 	}
-	subtypeObj.free();
       }
-      xObj.free();
-      xObjRef.free();
     }
   }
-  xObjDict.free();
 }
 
 void PSOutputDev::setupForm(Ref id, Object *strObj) {
   Dict *dict, *resDict;
-  Object matrixObj, bboxObj, resObj, obj1;
   double m[6], bbox[4];
   PDFRectangle box;
   Gfx *gfx;
-  int i;
 
   // check if form is already defined
-  for (i = 0; i < formIDLen; ++i) {
+  for (int i = 0; i < formIDLen; ++i) {
     if (formIDs[i].num == id.num && formIDs[i].gen == id.gen) {
       return;
     }
@@ -3206,36 +3167,31 @@
   dict = strObj->streamGetDict();
 
   // get bounding box
-  dict->lookup("BBox", &bboxObj);
+  Object bboxObj = dict->lookup("BBox");
   if (!bboxObj.isArray()) {
-    bboxObj.free();
     error(errSyntaxError, -1, "Bad form bounding box");
     return;
   }
-  for (i = 0; i < 4; ++i) {
-    bboxObj.arrayGet(i, &obj1);
+  for (int i = 0; i < 4; ++i) {
+    Object obj1 = bboxObj.arrayGet(i);
     bbox[i] = obj1.getNum();
-    obj1.free();
   }
-  bboxObj.free();
 
   // get matrix
-  dict->lookup("Matrix", &matrixObj);
+  Object matrixObj = dict->lookup("Matrix");
   if (matrixObj.isArray()) {
-    for (i = 0; i < 6; ++i) {
-      matrixObj.arrayGet(i, &obj1);
+    for (int i = 0; i < 6; ++i) {
+      Object obj1 = matrixObj.arrayGet(i);
       m[i] = obj1.getNum();
-      obj1.free();
     }
   } else {
     m[0] = 1; m[1] = 0;
     m[2] = 0; m[3] = 1;
     m[4] = 0; m[5] = 0;
   }
-  matrixObj.free();
 
   // get resources
-  dict->lookup("Resources", &resObj);
+  Object resObj = dict->lookup("Resources");
   resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
 
   writePSFmt("/f_{0:d}_{1:d} {{\n", id.num, id.gen);
@@ -3253,8 +3209,6 @@
 
   writePS("Q\n");
   writePS("} def\n");
-
-  resObj.free();
 }
 
 GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/,
@@ -3276,7 +3230,6 @@
   GfxState *state;
   SplashBitmap *bitmap;
   Stream *str0, *str;
-  Object obj;
   Guchar *p;
   Guchar col[4];
   double hDPI2, vDPI2;
@@ -3594,9 +3547,8 @@
     case psLevel2Sep:
     case psLevel3:
     case psLevel3Sep:
-      obj.initNull();
       p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize();
-      str0 = new MemStream((char *)p, 0, w * h * numComps, &obj);
+      str0 = new MemStream((char *)p, 0, w * h * numComps, Object(objNull));
       // Check for a color image that uses only gray
       if (!getOptimizeColorSpace()) {
 	isGray = gFalse;
@@ -6880,138 +6832,111 @@
 
 #if OPI_SUPPORT
 void PSOutputDev::opiBegin(GfxState *state, Dict *opiDict) {
-  Object dict;
-
   if (generateOPI) {
-    opiDict->lookup("2.0", &dict);
+    Object dict = opiDict->lookup("2.0");
     if (dict.isDict()) {
       opiBegin20(state, dict.getDict());
-      dict.free();
     } else {
-      dict.free();
-      opiDict->lookup("1.3", &dict);
+      dict = opiDict->lookup("1.3");
       if (dict.isDict()) {
 	opiBegin13(state, dict.getDict());
       }
-      dict.free();
     }
   }
 }
 
 void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) {
-  Object obj1, obj2, obj3, obj4;
   double width, height, left, right, top, bottom;
   int w, h;
-  int i;
 
   writePS("%%BeginOPI: 2.0\n");
   writePS("%%Distilled\n");
 
-  dict->lookup("F", &obj1);
-  if (getFileSpecName(&obj1, &obj2)) {
+  Object obj1 = dict->lookup("F");
+  Object obj2 = getFileSpecName(&obj1);
+  if (obj2.isString()) {
     writePSFmt("%%ImageFileName: {0:t}\n", obj2.getString());
-    obj2.free();
   }
-  obj1.free();
 
-  dict->lookup("MainImage", &obj1);
+  obj1 = dict->lookup("MainImage");
   if (obj1.isString()) {
     writePSFmt("%%MainImage: {0:t}\n", obj1.getString());
   }
-  obj1.free();
 
   //~ ignoring 'Tags' entry
   //~ need to use writePSString() and deal with >255-char lines
 
-  dict->lookup("Size", &obj1);
+  obj1 = dict->lookup("Size");
   if (obj1.isArray() && obj1.arrayGetLength() == 2) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     width = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     height = obj2.getNum();
-    obj2.free();
     writePSFmt("%%ImageDimensions: {0:.6g} {1:.6g}\n", width, height);
   }
-  obj1.free();
 
-  dict->lookup("CropRect", &obj1);
+  obj1 = dict->lookup("CropRect");
   if (obj1.isArray() && obj1.arrayGetLength() == 4) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     left = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     top = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(2, &obj2);
+    obj2 = obj1.arrayGet(2);
     right = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(3, &obj2);
+    obj2 = obj1.arrayGet(3);
     bottom = obj2.getNum();
-    obj2.free();
     writePSFmt("%%ImageCropRect: {0:.6g} {1:.6g} {2:.6g} {3:.6g}\n",
 	       left, top, right, bottom);
   }
-  obj1.free();
 
-  dict->lookup("Overprint", &obj1);
+  obj1 = dict->lookup("Overprint");
   if (obj1.isBool()) {
     writePSFmt("%%ImageOverprint: {0:s}\n", obj1.getBool() ? "true" : "false");
   }
-  obj1.free();
 
-  dict->lookup("Inks", &obj1);
+  obj1 = dict->lookup("Inks");
   if (obj1.isName()) {
     writePSFmt("%%ImageInks: {0:s}\n", obj1.getName());
   } else if (obj1.isArray() && obj1.arrayGetLength() >= 1) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     if (obj2.isName()) {
       writePSFmt("%%ImageInks: {0:s} {1:d}",
 		 obj2.getName(), (obj1.arrayGetLength() - 1) / 2);
-      for (i = 1; i+1 < obj1.arrayGetLength(); i += 2) {
-	obj1.arrayGet(i, &obj3);
-	obj1.arrayGet(i+1, &obj4);
+      for (int i = 1; i+1 < obj1.arrayGetLength(); i += 2) {
+	Object obj3 = obj1.arrayGet(i);
+	Object obj4 = obj1.arrayGet(i+1);
 	if (obj3.isString() && obj4.isNum()) {
 	  writePS(" ");
 	  writePSString(obj3.getString());
 	  writePSFmt(" {0:.6g}", obj4.getNum());
 	}
-	obj3.free();
-	obj4.free();
       }
       writePS("\n");
     }
-    obj2.free();
   }
-  obj1.free();
 
   writePS("gsave\n");
 
   writePS("%%BeginIncludedImage\n");
 
-  dict->lookup("IncludedImageDimensions", &obj1);
+  obj1 = dict->lookup("IncludedImageDimensions");
   if (obj1.isArray() && obj1.arrayGetLength() == 2) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     w = obj2.getInt();
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     h = obj2.getInt();
-    obj2.free();
     writePSFmt("%%IncludedImageDimensions: {0:d} {1:d}\n", w, h);
   }
-  obj1.free();
 
-  dict->lookup("IncludedImageQuality", &obj1);
+  obj1 = dict->lookup("IncludedImageQuality");
   if (obj1.isNum()) {
     writePSFmt("%%IncludedImageQuality: {0:.6g}\n", obj1.getNum());
   }
-  obj1.free();
 
   ++opi20Nest;
 }
 
 void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
-  Object obj1, obj2;
   int left, right, top, bottom, samples, bits, width, height;
   double c, m, y, k;
   double llx, lly, ulx, uly, urx, ury, lrx, lry;
@@ -7023,86 +6948,68 @@
   writePS("/opiMatrix2 matrix currentmatrix def\n");
   writePS("opiMatrix setmatrix\n");
 
-  dict->lookup("F", &obj1);
-  if (getFileSpecName(&obj1, &obj2)) {
+  Object obj1 = dict->lookup("F");
+  Object obj2 = getFileSpecName(&obj1);
+  if (obj2.isString()) {
     writePSFmt("%ALDImageFileName: {0:t}\n", obj2.getString());
-    obj2.free();
   }
-  obj1.free();
 
-  dict->lookup("CropRect", &obj1);
+  obj1 = dict->lookup("CropRect");
   if (obj1.isArray() && obj1.arrayGetLength() == 4) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     left = obj2.getInt();
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     top = obj2.getInt();
-    obj2.free();
-    obj1.arrayGet(2, &obj2);
+    obj2 = obj1.arrayGet(2);
     right = obj2.getInt();
-    obj2.free();
-    obj1.arrayGet(3, &obj2);
+    obj2 = obj1.arrayGet(3);
     bottom = obj2.getInt();
-    obj2.free();
     writePSFmt("%ALDImageCropRect: {0:d} {1:d} {2:d} {3:d}\n",
 	       left, top, right, bottom);
   }
-  obj1.free();
 
-  dict->lookup("Color", &obj1);
+  obj1 = dict->lookup("Color");
   if (obj1.isArray() && obj1.arrayGetLength() == 5) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     c = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     m = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(2, &obj2);
+    obj2 = obj1.arrayGet(2);
     y = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(3, &obj2);
+    obj2 = obj1.arrayGet(3);
     k = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(4, &obj2);
+    obj2 = obj1.arrayGet(4);
     if (obj2.isString()) {
       writePSFmt("%ALDImageColor: {0:.4g} {1:.4g} {2:.4g} {3:.4g} ",
 		 c, m, y, k);
       writePSString(obj2.getString());
       writePS("\n");
     }
-    obj2.free();
   }
-  obj1.free();
 
-  dict->lookup("ColorType", &obj1);
+  obj1 = dict->lookup("ColorType");
   if (obj1.isName()) {
     writePSFmt("%ALDImageColorType: {0:s}\n", obj1.getName());
   }
-  obj1.free();
 
   //~ ignores 'Comments' entry
   //~ need to handle multiple lines
 
-  dict->lookup("CropFixed", &obj1);
+  obj1 = dict->lookup("CropFixed");
   if (obj1.isArray()) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     ulx = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     uly = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(2, &obj2);
+    obj2 = obj1.arrayGet(2);
     lrx = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(3, &obj2);
+    obj2 = obj1.arrayGet(3);
     lry = obj2.getNum();
-    obj2.free();
     writePSFmt("%ALDImageCropFixed: {0:.6g} {1:.6g} {2:.6g} {3:.6g}\n",
 	       ulx, uly, lrx, lry);
   }
-  obj1.free();
 
-  dict->lookup("GrayMap", &obj1);
+  obj1 = dict->lookup("GrayMap");
   if (obj1.isArray()) {
     writePS("%ALDImageGrayMap:");
     for (i = 0; i < obj1.arrayGetLength(); i += 16) {
@@ -7110,116 +7017,90 @@
 	writePS("\n%%+");
       }
       for (j = 0; j < 16 && i+j < obj1.arrayGetLength(); ++j) {
-	obj1.arrayGet(i+j, &obj2);
+	obj2 = obj1.arrayGet(i+j);
 	writePSFmt(" {0:d}", obj2.getInt());
-	obj2.free();
       }
     }
     writePS("\n");
   }
-  obj1.free();
 
-  dict->lookup("ID", &obj1);
+  obj1 = dict->lookup("ID");
   if (obj1.isString()) {
     writePSFmt("%ALDImageID: {0:t}\n", obj1.getString());
   }
-  obj1.free();
 
-  dict->lookup("ImageType", &obj1);
+  obj1 = dict->lookup("ImageType");
   if (obj1.isArray() && obj1.arrayGetLength() == 2) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     samples = obj2.getInt();
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     bits = obj2.getInt();
-    obj2.free();
     writePSFmt("%ALDImageType: {0:d} {1:d}\n", samples, bits);
   }
-  obj1.free();
 
-  dict->lookup("Overprint", &obj1);
+  dict->lookup("Overprint");
   if (obj1.isBool()) {
     writePSFmt("%ALDImageOverprint: {0:s}\n",
 	       obj1.getBool() ? "true" : "false");
   }
-  obj1.free();
 
-  dict->lookup("Position", &obj1);
+  obj1 = dict->lookup("Position");
   if (obj1.isArray() && obj1.arrayGetLength() == 8) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     llx = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     lly = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(2, &obj2);
+    obj2 = obj1.arrayGet(2);
     ulx = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(3, &obj2);
+    obj2 = obj1.arrayGet(3);
     uly = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(4, &obj2);
+    obj2 = obj1.arrayGet(4);
     urx = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(5, &obj2);
+    obj2 = obj1.arrayGet(5);
     ury = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(6, &obj2);
+    obj2 = obj1.arrayGet(6);
     lrx = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(7, &obj2);
+    obj2 = obj1.arrayGet(7);
     lry = obj2.getNum();
-    obj2.free();
     opiTransform(state, llx, lly, &tllx, &tlly);
     opiTransform(state, ulx, uly, &tulx, &tuly);
     opiTransform(state, urx, ury, &turx, &tury);
     opiTransform(state, lrx, lry, &tlrx, &tlry);
     writePSFmt("%ALDImagePosition: {0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g} {6:.6g} {7:.6g}\n",
 	       tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry);
-    obj2.free();
   }
-  obj1.free();
 
-  dict->lookup("Resolution", &obj1);
+  obj1 = dict->lookup("Resolution");
   if (obj1.isArray() && obj1.arrayGetLength() == 2) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     horiz = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     vert = obj2.getNum();
-    obj2.free();
     writePSFmt("%ALDImageResoution: {0:.6g} {1:.6g}\n", horiz, vert);
-    obj2.free();
   }
-  obj1.free();
 
-  dict->lookup("Size", &obj1);
+  obj1 = dict->lookup("Size");
   if (obj1.isArray() && obj1.arrayGetLength() == 2) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     width = obj2.getInt();
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     height = obj2.getInt();
-    obj2.free();
     writePSFmt("%ALDImageDimensions: {0:d} {1:d}\n", width, height);
   }
-  obj1.free();
 
   //~ ignoring 'Tags' entry
   //~ need to use writePSString() and deal with >255-char lines
 
-  dict->lookup("Tint", &obj1);
+  obj1 = dict->lookup("Tint");
   if (obj1.isNum()) {
     writePSFmt("%ALDImageTint: {0:.6g}\n", obj1.getNum());
   }
-  obj1.free();
 
-  dict->lookup("Transparency", &obj1);
+  obj1 = dict->lookup("Transparency");
   if (obj1.isBool()) {
     writePSFmt("%ALDImageTransparency: {0:s}\n",
 	       obj1.getBool() ? "true" : "false");
   }
-  obj1.free();
 
   writePS("%%BeginObject: image\n");
   writePS("opiMatrix2 setmatrix\n");
@@ -7253,25 +7134,20 @@
 }
 
 void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) {
-  Object dict;
-
   if (generateOPI) {
-    opiDict->lookup("2.0", &dict);
+    Object dict = opiDict->lookup("2.0");
     if (dict.isDict()) {
       writePS("%%EndIncludedImage\n");
       writePS("%%EndOPI\n");
       writePS("grestore\n");
       --opi20Nest;
-      dict.free();
     } else {
-      dict.free();
-      opiDict->lookup("1.3", &dict);
+      dict = opiDict->lookup("1.3");
       if (dict.isDict()) {
 	writePS("%%EndObject\n");
 	writePS("restore\n");
 	--opi13Nest;
       }
-      dict.free();
     }
   }
 }
diff --git a/poppler/Page.cc b/poppler/Page.cc
index dca52e4..197e2be 100644
--- a/poppler/Page.cc
+++ b/poppler/Page.cc
@@ -15,7 +15,7 @@
 //
 // Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
 // Copyright (C) 2005 Jeff Muizelaar <jeff@infidigm.net>
-// Copyright (C) 2005-2013, 2016 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2005-2013, 2016, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2006-2008 Pino Toscano <pino@kde.org>
 // Copyright (C) 2006 Nickolay V. Shmyrev <nshmyrev@yandex.ru>
 // Copyright (C) 2006 Scott Turner <scotty1024@mac.com>
@@ -108,7 +108,7 @@
     cropBox = attrs->cropBox;
     haveCropBox = attrs->haveCropBox;
     rotate = attrs->rotate;
-    attrs->resources.copy(&resources);
+    resources = attrs->resources.copy();
   } else {
     // set default MediaBox to 8.5" x 11" -- this shouldn't be necessary
     // but some (non-compliant) PDF files don't specify a MediaBox
@@ -119,7 +119,7 @@
     cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0;
     haveCropBox = gFalse;
     rotate = 0;
-    resources.initNull();
+    resources.setToNull();
   }
 
   // media box
@@ -158,11 +158,10 @@
   readBox(dict, "ArtBox", &artBox);
 
   // rotate
-  dict->lookup("Rotate", &obj1);
+  obj1 = dict->lookup("Rotate");
   if (obj1.isInt()) {
     rotate = obj1.getInt();
   }
-  obj1.free();
   while (rotate < 0) {
     rotate += 360;
   }
@@ -171,30 +170,21 @@
   }
 
   // misc attributes
-  dict->lookup("LastModified", &lastModified);
-  dict->lookup("BoxColorInfo", &boxColorInfo);
-  dict->lookup("Group", &group);
-  dict->lookup("Metadata", &metadata);
-  dict->lookup("PieceInfo", &pieceInfo);
-  dict->lookup("SeparationInfo", &separationInfo);
+  lastModified = dict->lookup("LastModified");
+  boxColorInfo = dict->lookup("BoxColorInfo");
+  group = dict->lookup("Group");
+  metadata = dict->lookup("Metadata");
+  pieceInfo = dict->lookup("PieceInfo");
+  separationInfo = dict->lookup("SeparationInfo");
 
   // resource dictionary
-  dict->lookup("Resources", &obj1);
+  obj1 = dict->lookup("Resources");
   if (obj1.isDict()) {
-    resources.free();
-    obj1.copy(&resources);
+    resources = obj1.copy();
   }
-  obj1.free();
 }
 
 PageAttrs::~PageAttrs() {
-  lastModified.free();
-  boxColorInfo.free();
-  group.free();
-  metadata.free();
-  pieceInfo.free();
-  separationInfo.free();
-  resources.free();
 }
 
 void PageAttrs::clipBoxes() {
@@ -210,37 +200,33 @@
   Object obj1, obj2;
   GBool ok;
 
-  dict->lookup(key, &obj1);
+  obj1 = dict->lookup(key);
   if (obj1.isArray() && obj1.arrayGetLength() == 4) {
     ok = gTrue;
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     if (obj2.isNum()) {
       tmp.x1 = obj2.getNum();
     } else {
       ok = gFalse;
     }
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     if (obj2.isNum()) {
       tmp.y1 = obj2.getNum();
     } else {
       ok = gFalse;
     }
-    obj2.free();
-    obj1.arrayGet(2, &obj2);
+    obj2 = obj1.arrayGet(2);
     if (obj2.isNum()) {
       tmp.x2 = obj2.getNum();
     } else {
       ok = gFalse;
     }
-    obj2.free();
-    obj1.arrayGet(3, &obj2);
+    obj2 = obj1.arrayGet(3);
     if (obj2.isNum()) {
       tmp.y2 = obj2.getNum();
     } else {
       ok = gFalse;
     }
-    obj2.free();
     if (tmp.x1 == 0 && tmp.x2 == 0 && tmp.y1 == 0 && tmp.y2 == 0)
       ok = gFalse;
     if (ok) {
@@ -255,7 +241,6 @@
   } else {
     ok = gFalse;
   }
-  obj1.free();
   return ok;
 }
 
@@ -263,9 +248,7 @@
 // Page
 //------------------------------------------------------------------------
 
-Page::Page(PDFDoc *docA, int numA, Dict *pageDict, Ref pageRefA, PageAttrs *attrsA, Form *form) {
-  Object tmp;
-	
+Page::Page(PDFDoc *docA, int numA, Object *pageDict, Ref pageRefA, PageAttrs *attrsA, Form *form) {
 #if MULTITHREADED
   gInitMutex(&mutex);
 #endif
@@ -276,7 +259,7 @@
   duration = -1;
   annots = NULL;
 
-  pageObj.initDict(pageDict);
+  pageObj = pageDict->copy();
   pageRef = pageRefA;
 
   // get attributes
@@ -284,79 +267,67 @@
   attrs->clipBoxes();
 
   // transtion
-  pageDict->lookupNF("Trans", &trans);
+  trans = pageDict->dictLookupNF("Trans");
   if (!(trans.isRef() || trans.isDict() || trans.isNull())) {
     error(errSyntaxError, -1, "Page transition object (page {0:d}) is wrong type ({1:s})",
 	  num, trans.getTypeName());
-    trans.free();
+    trans = Object();
   }
 
   // duration
-  pageDict->lookupNF("Dur", &tmp);
+  Object tmp = pageDict->dictLookupNF("Dur");
   if (!(tmp.isNum() || tmp.isNull())) {
     error(errSyntaxError, -1, "Page duration object (page {0:d}) is wrong type ({1:s})",
 	  num, tmp.getTypeName());
   } else if (tmp.isNum()) {
     duration = tmp.getNum();
   }
-  tmp.free();
 
   // annotations
-  pageDict->lookupNF("Annots", &annotsObj);
+  annotsObj = pageDict->dictLookupNF("Annots");
   if (!(annotsObj.isRef() || annotsObj.isArray() || annotsObj.isNull())) {
     error(errSyntaxError, -1, "Page annotations object (page {0:d}) is wrong type ({1:s})",
 	  num, annotsObj.getTypeName());
-    annotsObj.free();
     goto err2;
   }
 
   // contents
-  pageDict->lookupNF("Contents", &contents);
+  contents = pageDict->dictLookupNF("Contents");
   if (!(contents.isRef() || contents.isArray() ||
 	contents.isNull())) {
     error(errSyntaxError, -1, "Page contents object (page {0:d}) is wrong type ({1:s})",
 	  num, contents.getTypeName());
-    contents.free();
     goto err1;
   }
 
   // thumb
-  pageDict->lookupNF("Thumb", &thumb);
+  thumb = pageDict->dictLookupNF("Thumb");
   if (!(thumb.isStream() || thumb.isNull() || thumb.isRef())) {
       error(errSyntaxError, -1, "Page thumb object (page {0:d}) is wrong type ({1:s})",
             num, thumb.getTypeName());
-      thumb.free();
-      thumb.initNull(); 
+      thumb.setToNull();
   }
 
   // actions
-  pageDict->lookupNF("AA", &actions);
+  actions = pageDict->dictLookupNF("AA");
   if (!(actions.isDict() || actions.isNull())) {
       error(errSyntaxError, -1, "Page additional action object (page {0:d}) is wrong type ({1:s})",
             num, actions.getTypeName());
-      actions.free();
-      actions.initNull();
+      actions.setToNull();
   }
   
   return;
 
-  trans.initNull();
  err2:
-  annotsObj.initNull();
+  annotsObj.setToNull();
  err1:
-  contents.initNull();
+  contents.setToNull();
   ok = gFalse;
 }
 
 Page::~Page() {
   delete attrs;
   delete annots;
-  pageObj.free();
-  annotsObj.free();
-  contents.free();
-  trans.free();
-  thumb.free();
-  actions.free();
 #if MULTITHREADED
   gDestroyMutex(&mutex);
 #endif
@@ -366,6 +337,11 @@
   return attrs->getResourceDict();
 }
 
+Object *Page::getResourceDictObject()
+{
+  return attrs->getResourceDictObject();
+}
+
 Dict *Page::getResourceDictCopy(XRef *xrefA) { 
   pageLocker();
   Dict *dict = attrs->getResourceDict();
@@ -376,42 +352,32 @@
   Object obj1;
   Dict *pageDict = pageObj.getDict()->copy(xrefA);
   xref = xrefA;
-  trans.free();
-  pageDict->lookupNF("Trans", &trans);
-  annotsObj.free();
-  pageDict->lookupNF("Annots", &annotsObj);
-  contents.free();
-  pageDict->lookupNF("Contents", &contents);
+  trans = pageDict->lookupNF("Trans");
+  annotsObj = pageDict->lookupNF("Annots");
+  contents = pageDict->lookupNF("Contents");
   if (contents.isArray()) {
-    contents.free();
-    pageDict->lookupNF("Contents", &obj1)->getArray()->copy(xrefA, &contents);
-    obj1.free();
+    obj1 = pageDict->lookupNF("Contents");
+    contents = obj1.getArray()->copy(xrefA);
   }
-  thumb.free();
-  pageDict->lookupNF("Thumb", &thumb);
-  actions.free();
-  pageDict->lookupNF("AA", &actions);
-  pageDict->lookup("Resources", &obj1);
+  thumb = pageDict->lookupNF("Thumb");
+  actions = pageDict->lookupNF("AA");
+  obj1 = pageDict->lookup("Resources");
   if (obj1.isDict()) {
-    attrs->replaceResource(obj1);
+    attrs->replaceResource(std::move(obj1));
   }
-  obj1.free();
   delete pageDict;
 }
 
 Annots *Page::getAnnots(XRef *xrefA) {
   if (!annots) {
-    Object obj;
-    annots = new Annots(doc, num, getAnnots(&obj, (xrefA == NULL) ? xref : xrefA));
-    obj.free();
+    Object obj = getAnnotsObject(xrefA);
+    annots = new Annots(doc, num, &obj);
   }
 
   return annots;
 }
 
 void Page::addAnnot(Annot *annot) {
-  Object obj1;
-  Object tmp;
   Ref annotRef = annot->getRef ();
 
   // Make sure we have annots before adding the new one
@@ -425,24 +391,22 @@
     // page doesn't have annots array,
     // we have to create it
 
-    obj1.initArray(xref);
-    obj1.arrayAdd(tmp.initRef (annotRef.num, annotRef.gen));
-    tmp.free();
+    Object obj1 = Object(new Array(xref));
+    obj1.arrayAdd(Object(annotRef.num, annotRef.gen));
 
     annotsRef = xref->addIndirectObject (&obj1);
-    annotsObj.initRef(annotsRef.num, annotsRef.gen);
-    pageObj.dictSet ("Annots", &annotsObj);
+    annotsObj = Object(annotsRef.num, annotsRef.gen);
+    pageObj.dictSet ("Annots", Object(annotsRef.num, annotsRef.gen));
     xref->setModifiedObject (&pageObj, pageRef);
   } else {
-    getAnnots(&obj1);
+    Object obj1 = getAnnotsObject();
     if (obj1.isArray()) {
-      obj1.arrayAdd (tmp.initRef (annotRef.num, annotRef.gen));
+      obj1.arrayAdd (Object(annotRef.num, annotRef.gen));
       if (annotsObj.isRef())
         xref->setModifiedObject (&obj1, annotsObj.getRef());
       else
         xref->setModifiedObject (&pageObj, pageRef);
     }
-    obj1.free();
   }
 
   // Popup annots are already handled by markup annots,
@@ -464,27 +428,24 @@
 
 void Page::removeAnnot(Annot *annot) {
   Ref annotRef = annot->getRef();
-  Object annArray;
 
   pageLocker();
-  getAnnots(&annArray);
+  Object annArray = getAnnotsObject();
   if (annArray.isArray()) {
     int idx = -1;
     // Get annotation position
     for (int i = 0; idx == -1 && i < annArray.arrayGetLength(); ++i) {
-      Object tmp;
-      if (annArray.arrayGetNF(i, &tmp)->isRef()) {
+      Object tmp = annArray.arrayGetNF(i);
+      if (tmp.isRef()) {
         Ref currAnnot = tmp.getRef();
         if (currAnnot.num == annotRef.num && currAnnot.gen == annotRef.gen) {
           idx = i;
         }
       }
-      tmp.free();
     }
 
     if (idx == -1) {
       error(errInternal, -1, "Annotation doesn't belong to this page");
-      annArray.free();
       return;
     }
     annots->removeAnnot(annot); // Gracefully fails on popup windows
@@ -497,7 +458,6 @@
       xref->setModifiedObject (&pageObj, pageRef);
     }
   }
-  annArray.free();
   annot->removeReferencedObjects(); // Note: Might recurse in removeAnnot again
   annot->setPage(0, gFalse);
 }
@@ -573,7 +533,6 @@
                         void *annotDisplayDecideCbkData,
                         GBool copyXRef) {
   Gfx *gfx;
-  Object obj;
   Annots *annotList;
   int i;
   
@@ -595,7 +554,7 @@
 		  printing,
 		  abortCheckCbk, abortCheckCbkData, localXRef);
 
-  contents.fetch(localXRef, &obj);
+  Object obj = contents.fetch(localXRef);
   if (!obj.isNull()) {
     gfx->saveState();
     gfx->display(&obj);
@@ -605,7 +564,6 @@
     // OutputDev
     out->dump();
   }
-  obj.free();
 
   // draw annotations
   annotList = getAnnots();
@@ -633,15 +591,12 @@
 }
 
 void Page::display(Gfx *gfx) {
-  Object obj;
-
-  contents.fetch(xref, &obj);
+  Object obj = contents.fetch(xref);
   if (!obj.isNull()) {
     gfx->saveState();
     gfx->display(&obj);
     gfx->restoreState();
   }
-  obj.free();
 }
 
 GBool Page::loadThumb(unsigned char **data_out,
@@ -650,7 +605,7 @@
 {
   unsigned int pixbufdatasize;
   int width, height, bits;
-  Object obj1, fetched_thumb;
+  Object obj1;
   Dict *dict;
   GfxColorSpace *colorSpace;
   GBool success = gFalse;
@@ -659,9 +614,8 @@
 
   /* Get stream dict */
   pageLocker();
-  thumb.fetch(xref, &fetched_thumb);
+  Object fetched_thumb = thumb.fetch(xref);
   if (!fetched_thumb.isStream()) {
-    fetched_thumb.free();
     return gFalse;
   }
 
@@ -683,25 +637,21 @@
   pixbufdatasize = width * height * 3;
 
   /* Get color space */
-  dict->lookup ("ColorSpace", &obj1);
+  obj1 = dict->lookup ("ColorSpace");
   if (obj1.isNull ()) {
-    obj1.free ();
-    dict->lookup ("CS", &obj1);
+    obj1 = dict->lookup ("CS");
   }
   colorSpace = GfxColorSpace::parse(NULL, &obj1, NULL, NULL);
-  obj1.free();
   if (!colorSpace) {
     fprintf (stderr, "Error: Cannot parse color space\n");
     goto fail1;
   }
 
-  dict->lookup("Decode", &obj1);
+  obj1 = dict->lookup("Decode");
   if (obj1.isNull()) {
-    obj1.free();
-    dict->lookup("D", &obj1);
+    obj1 = dict->lookup("D");
   }
   colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
-  obj1.free();
   if (!colorMap->isOk()) {
     fprintf (stderr, "Error: invalid colormap\n");
     delete colorMap;
@@ -744,8 +694,6 @@
 
   delete colorMap;
  fail1:
-  fetched_thumb.free();
-
   return success;
 }
 
@@ -842,21 +790,16 @@
 }
 
 LinkAction* Page::getAdditionalAction(PageAdditionalActionsType type) {
-  Object additionalActionsObject;
-  LinkAction *linkAction = NULL;
-
-  if (actions.fetch(doc->getXRef(), &additionalActionsObject)->isDict()) {
+  LinkAction *linkAction = nullptr;
+  Object additionalActionsObject = actions.fetch(doc->getXRef());
+  if (additionalActionsObject.isDict()) {
     const char *key = (type == actionOpenPage ?  "O" :
                        type == actionClosePage ? "C" : NULL);
 
-    Object actionObject;
-
-    if (additionalActionsObject.dictLookup(key, &actionObject)->isDict())
+    Object actionObject = additionalActionsObject.dictLookup(key);
+    if (actionObject.isDict())
       linkAction = LinkAction::parseAction(&actionObject, doc->getCatalog()->getBaseURI());
-    actionObject.free();
   }
 
-  additionalActionsObject.free();
-
   return linkAction;
 }
diff --git a/poppler/Page.h b/poppler/Page.h
index 2aaabae..2a59713 100644
--- a/poppler/Page.h
+++ b/poppler/Page.h
@@ -20,7 +20,7 @@
 // Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org>
 // Copyright (C) 2008 Iñigo Martínez <inigomartinez@gmail.com>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
-// Copyright (C) 2012 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2012, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
 // Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
 //
@@ -107,8 +107,10 @@
 	? separationInfo.getDict() : (Dict *)NULL; }
   Dict *getResourceDict()
     { return resources.isDict() ? resources.getDict() : (Dict *)NULL; }
-  void replaceResource(Object obj1) 
-  {  resources.free(); obj1.copy(&resources); }
+  Object *getResourceDictObject()
+    { return &resources; }
+  void replaceResource(Object &&obj1)
+  {  resources = std::move(obj1); }
 
   // Clip all other boxes to the MediaBox.
   void clipBoxes();
@@ -141,7 +143,7 @@
 public:
 
   // Constructor.
-  Page(PDFDoc *docA, int numA, Dict *pageDict, Ref pageRefA, PageAttrs *attrsA, Form *form);
+  Page(PDFDoc *docA, int numA, Object *pageDict, Ref pageRefA, PageAttrs *attrsA, Form *form);
 
   // Destructor.
   ~Page();
@@ -177,10 +179,11 @@
 
   // Get resource dictionary.
   Dict *getResourceDict();
+  Object *getResourceDictObject();
   Dict *getResourceDictCopy(XRef *xrefA);
 
   // Get annotations array.
-  Object *getAnnots(Object *obj, XRef *xrefA = NULL) { return annotsObj.fetch((xrefA == NULL) ? xref : xrefA, obj); }
+  Object getAnnotsObject(XRef *xrefA = nullptr) { return annotsObj.fetch(xrefA ? xrefA : xref); }
   // Add a new annotation to the page
   void addAnnot(Annot *annot);
   // Remove an existing annotation from the page
@@ -193,14 +196,14 @@
   Annots *getAnnots(XRef *xrefA = NULL);
 
   // Get contents.
-  Object *getContents(Object *obj) { return contents.fetch(xref, obj); }
+  Object getContents() { return contents.fetch(xref); }
 
   // Get thumb.
-  Object *getThumb(Object *obj) { return thumb.fetch(xref, obj); }
+  Object getThumb() { return thumb.fetch(xref); }
   GBool loadThumb(unsigned char **data, int *width, int *height, int *rowstride);
 
   // Get transition.
-  Object *getTrans(Object *obj) { return trans.fetch(xref, obj); }
+  Object getTrans() { return trans.fetch(xref); }
 
   // Get form.
   FormPageWidgets *getFormWidgets();
@@ -211,7 +214,7 @@
   double getDuration() { return duration; }
 
   // Get actions
-  Object *getActions(Object *obj) { return actions.fetch(xref, obj); }
+  Object getActions() { return actions.fetch(xref); }
 
   enum PageAdditionalActionsType {
     actionOpenPage,     ///< Performed when opening the page
diff --git a/poppler/PageLabelInfo.cc b/poppler/PageLabelInfo.cc
index 3153377..d771024 100644
--- a/poppler/PageLabelInfo.cc
+++ b/poppler/PageLabelInfo.cc
@@ -3,7 +3,7 @@
 // This file is under the GPLv2 or later license
 //
 // Copyright (C) 2005-2006 Kristian Høgsberg <krh@redhat.com>
-// Copyright (C) 2005, 2009, 2013 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2005, 2009, 2013, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2011 Simon Kellner <kellner@kit.edu>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
 //
@@ -22,10 +22,9 @@
 #include "PageLabelInfo_p.h"
 
 PageLabelInfo::Interval::Interval(Object *dict, int baseA) {
-  Object obj;
-
   style = None;
-  if (dict->dictLookup("S", &obj)->isName()) {
+  Object obj = dict->dictLookup("S");
+  if (obj.isName()) {
     if (obj.isName("D")) {
       style = Arabic;
     } else if (obj.isName("R")) {
@@ -38,19 +37,18 @@
       style = LowercaseLatin;
     }
   }
-  obj.free();
 
-  if (dict->dictLookup("P", &obj)->isString())
+  obj = dict->dictLookup("P");
+  if (obj.isString())
     prefix = obj.getString()->copy();
   else
     prefix = new GooString("");
-  obj.free();
 
-  if (dict->dictLookup("St", &obj)->isInt())
+  obj = dict->dictLookup("St");
+  if (obj.isInt())
     first = obj.getInt();
   else
     first = 1;
-  obj.free();
 
   base = baseA;
 }
@@ -86,40 +84,32 @@
 }
 
 void PageLabelInfo::parse(Object *tree) {
-  Object nums, obj;
-  Object kids, kid, limits, low, high;
-  int i, base;
-  Interval *interval;
-
   // leaf node
-  if (tree->dictLookup("Nums", &nums)->isArray()) {
-    for (i = 0; i < nums.arrayGetLength(); i += 2) {
-      if (!nums.arrayGet(i, &obj)->isInt()) {
-	obj.free();
+  Object nums = tree->dictLookup("Nums");
+  if (nums.isArray()) {
+    for (int i = 0; i < nums.arrayGetLength(); i += 2) {
+      Object obj = nums.arrayGet(i);
+      if (!obj.isInt()) {
 	continue;
       }
-      base = obj.getInt();
-      obj.free();
-      if (!nums.arrayGet(i + 1, &obj)->isDict()) {
-	obj.free();
+      int base = obj.getInt();
+      obj = nums.arrayGet(i + 1);
+      if (!obj.isDict()) {
 	continue;
       }
 
-      interval = new Interval(&obj, base);
-      obj.free();
-      intervals.append(interval);
+      intervals.append(new Interval(&obj, base));
     }
   }
-  nums.free();
 
-  if (tree->dictLookup("Kids", &kids)->isArray()) {
-    for (i = 0; i < kids.arrayGetLength(); ++i) {
-      if (kids.arrayGet(i, &kid)->isDict())
+  Object kids = tree->dictLookup("Kids");
+  if (kids.isArray()) {
+    for (int i = 0; i < kids.arrayGetLength(); ++i) {
+      Object kid = kids.arrayGet(i);
+      if (kid.isDict())
 	parse(&kid);
-      kid.free();
     }
   }
-  kids.free();
 }
 
 GBool PageLabelInfo::labelToIndex(GooString *label, int *index)
diff --git a/poppler/PageTransition.cc b/poppler/PageTransition.cc
index d5a84f8..07a2c65 100644
--- a/poppler/PageTransition.cc
+++ b/poppler/PageTransition.cc
@@ -1,6 +1,6 @@
 /* PageTransition.cc
  * Copyright (C) 2005, Net Integration Technologies, Inc.
- * Copyright (C) 2010, Albert Astals Cid <aacid@kde.org>
+ * Copyright (C) 2010, 2017, Albert Astals Cid <aacid@kde.org>
  * Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
  * Copyright (C) 2015, Arseniy Lartsev <arseniy@alumni.chalmers.se>
  *
@@ -50,7 +50,8 @@
   dict = trans->getDict();
 
   // get type
-  if (dict->lookup("S", &obj)->isName()) {
+  obj = dict->lookup("S");
+  if (obj.isName()) {
     const char *s = obj.getName();
     
     if (strcmp("R", s) == 0)
@@ -78,16 +79,16 @@
     else if (strcmp("Fade", s) == 0)
       type = transitionFade;
   }
-  obj.free();
 
   // get duration
-  if (dict->lookup("D", &obj)->isNum()) {
+  obj = dict->lookup("D");
+  if (obj.isNum()) {
     duration = obj.getNum();
   }
-  obj.free();
 
   // get alignment
-  if (dict->lookup("Dm", &obj)->isName()) {
+  obj = dict->lookup("Dm");
+  if (obj.isName()) {
     const char *dm = obj.getName();
     
     if (strcmp("H", dm) == 0)
@@ -95,10 +96,10 @@
     else if (strcmp("V", dm) == 0)
       alignment = transitionVertical;
   }
-  obj.free();
 
   // get direction
-  if (dict->lookup("M", &obj)->isName()) {
+  obj = dict->lookup("M");
+  if (obj.isName()) {
     const char *m = obj.getName();
     
     if (strcmp("I", m) == 0)
@@ -106,31 +107,30 @@
     else if (strcmp("O", m) == 0)
       direction = transitionOutward;
   }
-  obj.free();
 
   // get angle
-  if (dict->lookup("Di", &obj)->isInt()) {
+  obj = dict->lookup("Di");
+  if (obj.isInt()) {
     angle = obj.getInt();
   }
-  obj.free();
 
-  if (dict->lookup("Di", &obj)->isName()) {
+  obj = dict->lookup("Di");
+  if (obj.isName()) {
     if (strcmp("None", obj.getName()) == 0)
       angle = 0;
   }
-  obj.free();
 
   // get scale
-  if (dict->lookup("SS", &obj)->isNum()) {
+  obj = dict->lookup("SS");
+  if (obj.isNum()) {
     scale = obj.getNum();
   }
-  obj.free();
 
   // get rectangular
-  if (dict->lookup("B", &obj)->isBool()) {
+  obj = dict->lookup("B");
+  if (obj.isBool()) {
     rectangular = obj.getBool();
   }
-  obj.free();
 }
 
 PageTransition::~PageTransition()
diff --git a/poppler/Parser.cc b/poppler/Parser.cc
index 8079ca1..07e220f 100644
--- a/poppler/Parser.cc
+++ b/poppler/Parser.cc
@@ -50,56 +50,50 @@
   lexer = lexerA;
   inlineImg = 0;
   allowStreams = allowStreamsA;
-  lexer->getObj(&buf1);
-  lexer->getObj(&buf2);
+  buf1 = lexer->getObj();
+  buf2 = lexer->getObj();
 }
 
 Parser::~Parser() {
-  buf1.free();
-  buf2.free();
   delete lexer;
 }
 
-Object *Parser::getObj(Object *obj, int recursion)
+Object Parser::getObj(int recursion)
 {
-  return getObj(obj, gFalse, NULL, cryptRC4, 0, 0, 0, recursion);
+  return getObj(gFalse, NULL, cryptRC4, 0, 0, 0, recursion);
 }
 
-Object *Parser::getObj(Object *obj, GBool simpleOnly,
+Object Parser::getObj(GBool simpleOnly,
            Guchar *fileKey,
 		       CryptAlgorithm encAlgorithm, int keyLength,
 		       int objNum, int objGen, int recursion,
 		       GBool strict) {
+  Object obj;
   char *key;
   Stream *str;
-  Object obj2;
-  int num;
   DecryptStream *decrypt;
   GooString *s, *s2;
   int c;
 
   // refill buffer after inline image data
   if (inlineImg == 2) {
-    buf1.free();
-    buf2.free();
-    lexer->getObj(&buf1);
-    lexer->getObj(&buf2);
+    buf1 = lexer->getObj();
+    buf2 = lexer->getObj();
     inlineImg = 0;
   }
 
   if (unlikely(recursion >= recursionLimit)) {
-    obj->free();
-    obj->initError();
-    return obj;
+    return Object(objError);
   }
 
   // array
   if (!simpleOnly && buf1.isCmd("[")) {
     shift();
-    obj->initArray(xref);
-    while (!buf1.isCmd("]") && !buf1.isEOF())
-      obj->arrayAdd(getObj(&obj2, gFalse, fileKey, encAlgorithm, keyLength,
-			   objNum, objGen, recursion + 1));
+    obj = Object(new Array(xref));
+    while (!buf1.isCmd("]") && !buf1.isEOF()) {
+      Object obj2 = getObj(gFalse, fileKey, encAlgorithm, keyLength, objNum, objGen, recursion + 1);
+      obj.arrayAdd(std::move(obj2));
+    }
     if (buf1.isEOF()) {
       error(errSyntaxError, getPos(), "End of file inside array");
       if (strict) goto err;
@@ -109,7 +103,7 @@
   // dictionary or stream
   } else if (!simpleOnly && buf1.isCmd("<<")) {
     shift(objNum);
-    obj->initDict(xref);
+    obj = Object(new Dict(xref));
     while (!buf1.isCmd(">>") && !buf1.isEOF()) {
       if (!buf1.isName()) {
 	error(errSyntaxError, getPos(), "Dictionary key must be a name object");
@@ -124,10 +118,11 @@
 	  if (strict && buf1.isError()) goto err;
 	  break;
 	}
-	obj->dictAdd(key, getObj(&obj2, gFalse, fileKey, encAlgorithm, keyLength, objNum, objGen, recursion + 1));
+	Object obj2 = getObj(gFalse, fileKey, encAlgorithm, keyLength, objNum, objGen, recursion + 1);
 	if (unlikely(obj2.isError() && recursion + 1 >= recursionLimit)) {
 	  break;
 	}
+	obj.dictAdd(key, std::move(obj2));
       }
     }
     if (buf1.isEOF()) {
@@ -137,13 +132,12 @@
     // stream objects are not allowed inside content streams or
     // object streams
     if (buf2.isCmd("stream")) {
-      if (allowStreams && (str = makeStream(obj, fileKey, encAlgorithm, keyLength,
+      if (allowStreams && (str = makeStream(std::move(obj), fileKey, encAlgorithm, keyLength,
                                             objNum, objGen, recursion + 1,
                                             strict))) {
-        obj->initStream(str);
+        return Object(str);
       } else {
-        obj->free();
-        obj->initError();
+        return Object(objError);
       }
     } else {
       shift();
@@ -151,23 +145,22 @@
 
   // indirect reference or integer
   } else if (buf1.isInt()) {
-    num = buf1.getInt();
+    const int num = buf1.getInt();
     shift();
     if (buf1.isInt() && buf2.isCmd("R")) {
-      obj->initRef(num, buf1.getInt());
+      const int gen = buf1.getInt();
       shift();
       shift();
+      return Object(num, gen);
     } else {
-      obj->initInt(num);
+      return Object(num);
     }
 
   // string
   } else if (buf1.isString() && fileKey) {
     s = buf1.getString();
     s2 = new GooString();
-    obj2.initNull();
-    decrypt = new DecryptStream(new MemStream(s->getCString(), 0,
-					      s->getLength(), &obj2),
+    decrypt = new DecryptStream(new MemStream(s->getCString(), 0, s->getLength(), Object(objNull)),
 				fileKey, encAlgorithm, keyLength,
 				objNum, objGen);
     decrypt->reset();
@@ -175,7 +168,7 @@
       s2->append((char)c);
     }
     delete decrypt;
-    obj->initString(s2);
+    obj = Object(s2);
     shift();
 
   // simple object
@@ -183,25 +176,20 @@
     // avoid re-allocating memory for complex objects like strings by
     // shallow copy of <buf1> to <obj> and nulling <buf1> so that
     // subsequent buf1.free() won't free this memory
-    buf1.shallowCopy(obj);
-    buf1.initNull();
+    obj = std::move(buf1);
     shift();
   }
 
   return obj;
 
 err:
-  obj->free();
-  obj->initError();
-  return obj;
-
+  return Object(objError);
 }
 
-Stream *Parser::makeStream(Object *dict, Guchar *fileKey,
+Stream *Parser::makeStream(Object &&dict, Guchar *fileKey,
 			   CryptAlgorithm encAlgorithm, int keyLength,
 			   int objNum, int objGen, int recursion,
                            GBool strict) {
-  Object obj;
   BaseStream *baseStr;
   Stream *str;
   Goffset length;
@@ -215,16 +203,13 @@
   pos = str->getPos();
 
   // get length
-  dict->dictLookup("Length", &obj, recursion);
+  Object obj = dict.dictLookup("Length", recursion);
   if (obj.isInt()) {
     length = obj.getInt();
-    obj.free();
   } else if (obj.isInt64()) {
     length = obj.getInt64();
-    obj.free();
   } else {
     error(errSyntaxError, getPos(), "Bad 'Length' attribute in stream");
-    obj.free();
     if (strict) return NULL;
     length = 0;
   }
@@ -261,9 +246,7 @@
       // shift until we find the proper endstream or we change to another object or reach eof
       length = lexer->getPos() - pos;
       if (buf1.isCmd("endstream")) {
-        obj.initInt64(length);
-        dict->dictSet("Length", &obj);
-        obj.free();
+        dict.dictSet("Length", Object(length));
       }
     } else {
       // When building the xref we can't use it so use this
@@ -274,7 +257,7 @@
   }
 
   // make base stream
-  str = baseStr->makeSubStream(pos, gTrue, length, dict);
+  str = baseStr->makeSubStream(pos, gTrue, length, std::move(dict));
 
   // handle decryption
   if (fileKey) {
@@ -283,7 +266,7 @@
   }
 
   // get filters
-  str = str->addFilters(dict, recursion);
+  str = str->addFilters(str->getDict(), recursion);
 
   return str;
 }
@@ -301,12 +284,12 @@
     lexer->skipChar();		// skip char after 'ID' command
     inlineImg = 1;
   }
-  buf1.free();
-  buf2.shallowCopy(&buf1);
+  buf1 = std::move(buf2);
   if (inlineImg > 0)		// don't buffer inline image data
-    buf2.initNull();
-  else
-    lexer->getObj(&buf2, objNum);
+    buf2.setToNull();
+  else {
+    buf2 = lexer->getObj(objNum);
+  }
 }
 
 void Parser::shift(const char *cmdA, int objNum) {
@@ -322,13 +305,12 @@
     lexer->skipChar();		// skip char after 'ID' command
     inlineImg = 1;
   }
-  buf1.free();
-  buf2.shallowCopy(&buf1);
+  buf1 = std::move(buf2);
   if (inlineImg > 0) {
-    buf2.initNull();
+    buf2.setToNull();
   } else if (buf1.isCmd(cmdA)) {
-    lexer->getObj(&buf2, objNum);
+    buf2 = lexer->getObj(objNum);
   } else {
-    lexer->getObj(&buf2, cmdA, objNum);
+    buf2 = lexer->getObj(cmdA, objNum);
   }
 }
diff --git a/poppler/Parser.h b/poppler/Parser.h
index 1ce9445..d275110 100644
--- a/poppler/Parser.h
+++ b/poppler/Parser.h
@@ -13,7 +13,7 @@
 // All changes made under the Poppler project to this file are licensed
 // under GPL version 2 or later
 //
-// Copyright (C) 2006, 2010, 2013 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006, 2010, 2013, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2012 Hib Eris <hib@hiberis.nl>
 // Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
 // Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
@@ -48,13 +48,14 @@
   // Get the next object from the input stream.  If <simpleOnly> is
   // true, do not parse compound objects (arrays, dictionaries, or
   // streams).
-  Object *getObj(Object *obj, GBool simpleOnly = gFalse, 
+  Object getObj(GBool simpleOnly = gFalse,
      Guchar *fileKey = NULL,
 		 CryptAlgorithm encAlgorithm = cryptRC4, int keyLength = 0,
 		 int objNum = 0, int objGen = 0, int recursion = 0,
 		 GBool strict = gFalse);
   
-  Object *getObj(Object *obj, int recursion);
+  Object getObj(int recursion);
+  template<typename T> Object getObj(T) = delete;
 
   // Get stream.
   Stream *getStream() { return lexer->getStream(); }
@@ -70,7 +71,7 @@
   Object buf1, buf2;		// next two tokens
   int inlineImg;		// set when inline image data is encountered
 
-  Stream *makeStream(Object *dict, Guchar *fileKey,
+  Stream *makeStream(Object &&dict, Guchar *fileKey,
 		     CryptAlgorithm encAlgorithm, int keyLength,
 		     int objNum, int objGen, int recursion,
 		     GBool strict);
diff --git a/poppler/PopplerCache.cc b/poppler/PopplerCache.cc
index 970c003..4fa0a44 100644
--- a/poppler/PopplerCache.cc
+++ b/poppler/PopplerCache.cc
@@ -5,7 +5,7 @@
 // This file is licensed under the GPLv2 or later
 //
 // Copyright (C) 2009 Koji Otani <sho@bbr.jp>
-// Copyright (C) 2009, 2010 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2009, 2010, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2010 Carlos Garcia Campos <carlosgc@gnome.org>
 //
 //========================================================================
@@ -121,14 +121,9 @@
 
 class ObjectItem : public PopplerCacheItem {
   public:
-    ObjectItem(Object *obj)
+    ObjectItem(Object &&obj)
     {
-      obj->copy(&item);
-    }
-
-    ~ObjectItem()
-    {
-      item.free();
+      item = std::move(obj);
     }
 
     Object item;
@@ -144,20 +139,18 @@
 }
 
 Object *PopplerObjectCache::put(const Ref &ref) {
-  Object obj;
-  xref->fetch(ref.num, ref.gen, &obj);
+  Object obj = xref->fetch(ref.num, ref.gen);
 
   ObjectKey *key = new ObjectKey(ref.num, ref.gen);
-  ObjectItem *item = new ObjectItem(&obj);
+  ObjectItem *item = new ObjectItem(std::move(obj));
   cache->put(key, item);
-  obj.free();
 
   return &item->item;
 }
 
-Object *PopplerObjectCache::lookup(const Ref &ref, Object *obj) {
+Object PopplerObjectCache::lookup(const Ref &ref) {
   ObjectKey key(ref.num, ref.gen);
   ObjectItem *item = static_cast<ObjectItem *>(cache->lookup(key));
 
-  return item ? item->item.copy(obj) : obj->initNull();
+  return item ? item->item.copy() : Object(objNull);
 }
diff --git a/poppler/PopplerCache.h b/poppler/PopplerCache.h
index 74010a2..f9d8a1d 100644
--- a/poppler/PopplerCache.h
+++ b/poppler/PopplerCache.h
@@ -5,7 +5,7 @@
 // This file is licensed under the GPLv2 or later
 //
 // Copyright (C) 2009 Koji Otani <sho@bbr.jp>
-// Copyright (C) 2009, 2010 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2009, 2010, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2010 Carlos Garcia Campos <carlosgc@gnome.org>
 //
 //========================================================================
@@ -68,7 +68,7 @@
     ~PopplerObjectCache();
 
     Object *put(const Ref &ref);
-    Object *lookup(const Ref &ref, Object *obj);
+    Object lookup(const Ref &ref);
 
   private:
     XRef *xref;
diff --git a/poppler/Rendition.cc b/poppler/Rendition.cc
index c040bf2..89bf1a5 100644
--- a/poppler/Rendition.cc
+++ b/poppler/Rendition.cc
@@ -7,6 +7,7 @@
 // Pino Toscano <pino@kde.org> (c) 2008
 // Carlos Garcia Campos <carlosgc@gnome.org> (c) 2010
 // Tobias Koenig <tobias.koenig@kdab.com> (c) 2012
+// Albert Astals Cid <aacid@kde.org> (C) 2017
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License as published by
@@ -44,26 +45,26 @@
 }
 
 void MediaWindowParameters::parseFWParams(Object* obj) {
-  Object tmp;
-
-  if (obj->dictLookup("D", &tmp)->isArray()) {
+  Object tmp = obj->dictLookup("D");
+  if (tmp.isArray()) {
     Array * dim = tmp.getArray();
     
     if (dim->getLength() >= 2) {
-      Object dd;
-      if (dim->get(0, &dd)->isInt()) {
+      Object dd = dim->get(0);
+      if (dd.isInt()) {
 	width = dd.getInt();
       }
-      dd.free();
-      if (dim->get(1, &dd)->isInt()) {
+
+      dd = dim->get(1);
+      if (dd.isInt()) {
 	height = dd.getInt();
       }
-      dd.free();
+
     }
   }
-  tmp.free();
 
-  if (obj->dictLookup("RT", &tmp)->isInt()) {
+  tmp = obj->dictLookup("RT");
+  if (tmp.isInt()) {
     int t = tmp.getInt();
     switch(t) {
     case 0: relativeTo = windowRelativeToDocument; break;
@@ -71,9 +72,9 @@
     case 2: relativeTo = windowRelativeToDesktop; break;
     }
   }
-  tmp.free();
 
-  if (obj->dictLookup("P",&tmp)->isInt()) {
+  tmp = obj->dictLookup("P");
+  if (tmp.isInt()) {
     int t = tmp.getInt();
 
     switch(t) {
@@ -115,21 +116,19 @@
       break;
     }
   }
-  tmp.free();
 
-  if (obj->dictLookup("T", &tmp)->isBool()) {
+  tmp = obj->dictLookup("T");
+  if (tmp.isBool()) {
     hasTitleBar = tmp.getBool();
   }
-  tmp.free();
-  if (obj->dictLookup("UC", &tmp)->isBool()) {
+  tmp = obj->dictLookup("UC");
+  if (tmp.isBool()) {
     hasCloseButton = tmp.getBool();
   }
-  tmp.free();
-  if (obj->dictLookup("R", &tmp)->isInt()) {
+  tmp = obj->dictLookup("R");
+  if (tmp.isInt()) {
     isResizeable = (tmp.getInt() != 0);
   }
-  tmp.free();
-
 }
 
 MediaParameters::MediaParameters() {
@@ -148,20 +147,18 @@
 }
 
 void MediaParameters::parseMediaPlayParameters(Object* obj) {
-  
-  Object tmp;
-
-  if (obj->dictLookup("V", &tmp)->isInt()) {
+  Object tmp = obj->dictLookup("V");
+  if (tmp.isInt()) {
     volume = tmp.getInt();
   }
-  tmp.free();
 
-  if (obj->dictLookup("C", &tmp)->isBool()) {
+  tmp = obj->dictLookup("C");
+  if (tmp.isBool()) {
     showControls = tmp.getBool();
   }
-  tmp.free();
 
-  if (obj->dictLookup("F", &tmp)->isInt()) {
+  tmp = obj->dictLookup("F");
+  if (tmp.isInt()) {
     int t = tmp.getInt();
     
     switch(t) {
@@ -173,47 +170,42 @@
     case 5: fittingPolicy = fittingUndefined; break;
     }
   }
-  tmp.free();
 
   // duration parsing
   // duration's default value is set to 0, which means : intrinsinc media duration
-  if (obj->dictLookup("D", &tmp)->isDict()) {
-    Object oname, ddict, tmp2;
-    if (tmp.dictLookup("S", &oname)->isName()) {
+  tmp = obj->dictLookup("D");
+  if (tmp.isDict()) {
+    Object oname = tmp.dictLookup("S");
+    if (oname.isName()) {
       char* name = oname.getName();
       if (!strcmp(name, "F"))
 	duration = -1; // infinity
       else if (!strcmp(name, "T")) {
-	if (tmp.dictLookup("T", &ddict)->isDict()) {
-	  if (ddict.dictLookup("V", &tmp2)->isNum()) {
+	Object ddict = tmp.dictLookup("T");
+	if (ddict.isDict()) {
+	  Object tmp2 = ddict.dictLookup("V");
+	  if (tmp2.isNum()) {
 	    duration = Gulong(tmp2.getNum());
 	  }
-	  tmp2.free();
 	}
-	ddict.free();
       }
     }
-    oname.free();
   }
-  tmp.free();
 
-
-  if (obj->dictLookup("A", &tmp)->isBool()) {
+  tmp = obj->dictLookup("A");
+  if (tmp.isBool()) {
     autoPlay = tmp.getBool();
   }
-  tmp.free();
 
-  if (obj->dictLookup("RC", &tmp)->isNum()) {
+  tmp = obj->dictLookup("RC");
+  if (tmp.isNum()) {
     repeatCount = tmp.getNum();
   }
-  tmp.free();
-
 }
 
 void MediaParameters::parseMediaScreenParameters(Object* obj) {
-  Object tmp;
-
-  if (obj->dictLookup("W", &tmp)->isInt()) {
+  Object tmp = obj->dictLookup("W");
+  if (tmp.isInt()) {
     int t = tmp.getInt();
     
     switch(t) {
@@ -223,102 +215,84 @@
     case 3: windowParams.type = MediaWindowParameters::windowEmbedded; break;
     }
   }
-  tmp.free();
 
   // background color
-  if (obj->dictLookup("B", &tmp)->isArray()) {
+  tmp = obj->dictLookup("B");
+  if (tmp.isArray()) {
     Array* color = tmp.getArray();
 
-    Object component;
-    
-    color->get(0, &component);
+    Object component = color->get(0);
     bgColor.r = component.getNum();
-    component.free();
 
-    color->get(1, &component);
+    component = color->get(1);
     bgColor.g = component.getNum();
-    component.free();
 
-    color->get(2, &component);
+    component = color->get(2);
     bgColor.b = component.getNum();
-    component.free();
   }
-  tmp.free();
-
 
   // opacity
-  if (obj->dictLookup("O", &tmp)->isNum()) {
+  tmp = obj->dictLookup("O");
+  if (tmp.isNum()) {
     opacity = tmp.getNum();
   }
-  tmp.free();
 
   if (windowParams.type == MediaWindowParameters::windowFloating) {
-    Object winDict;
-    if (obj->dictLookup("F",&winDict)->isDict()) {
+    Object winDict = obj->dictLookup("F");
+    if (winDict.isDict()) {
       windowParams.parseFWParams(&winDict);
     }
-    winDict.free();
   }
 }
 
 MediaRendition::~MediaRendition() {
-  if (fileName)
-    delete fileName;
-  if (contentType)
-    delete contentType;
-
-  if (embeddedStream && (!embeddedStream->decRef())) {
-    delete embeddedStream;
-  }
+  delete fileName;
+  delete contentType;
 }
 
 MediaRendition::MediaRendition(Object* obj) {
-  Object tmp, tmp2;
   GBool hasClip = gFalse;
 
   ok = gTrue;
   fileName = NULL;
   contentType = NULL;
   isEmbedded = gFalse;
-  embeddedStream = NULL;
 
   //
   // Parse media clip data
   //
-  if (obj->dictLookup("C", &tmp2)->isDict()) { // media clip
+  Object tmp2 = obj->dictLookup("C");
+  if (tmp2.isDict()) { // media clip
     hasClip = gTrue;
-    if (tmp2.dictLookup("S", &tmp)->isName()) {
+    Object tmp = tmp2.dictLookup("S");
+    if (tmp.isName()) {
       if (!strcmp(tmp.getName(), "MCD")) { // media clip data
-        Object obj1, obj2;
-	if (tmp2.dictLookup("D", &obj1)->isDict()) {
-	  if (obj1.dictLookup("F", &obj2)->isString()) {
+        Object obj1 = tmp2.dictLookup("D");
+	if (obj1.isDict()) {
+	  Object obj2 = obj1.dictLookup("F");
+	  if (obj2.isString()) {
 	    fileName = obj2.getString()->copy();
 	  }
-	  obj2.free();
-	  if (obj1.dictLookup("EF", &obj2)->isDict()) {
-	    Object embedded;
-	    if (obj2.dictLookup("F", &embedded)->isStream()) {
+	  obj2 = obj1.dictLookup("EF");
+	  if (obj2.isDict()) {
+	    Object embedded = obj2.dictLookup("F");
+	    if (embedded.isStream()) {
 	      isEmbedded = gTrue;
-	      embeddedStream = embedded.getStream();
-	      // "copy" stream
-	      embeddedStream->incRef();
+	      embeddedStreamObject = embedded.copy();
 	    }
-	    embedded.free();
 	  }
-	  obj2.free();
 
 	  // TODO: D might be a form XObject too
 	} else {
 	  error (errSyntaxError, -1, "Invalid Media Clip Data");
 	  ok = gFalse;
 	}
-	obj1.free();
 
 	// FIXME: ignore CT if D is a form XObject
-	if (tmp2.dictLookup("CT", &obj1)->isString()) {
+	obj1 = tmp2.dictLookup("CT");
+	if (obj1.isString()) {
 	  contentType = obj1.getString()->copy();
 	}
-	obj1.free();
       } else if (!strcmp(tmp.getName(), "MCS")) { // media clip data
         // TODO
       }
@@ -326,55 +300,69 @@
       error (errSyntaxError, -1, "Invalid Media Clip");
       ok = gFalse;
     }
-    tmp.free();
   }
-  tmp2.free();
 
   if (!ok)
     return;
 
   //
   // parse Media Play Parameters
-  if (obj->dictLookup("P", &tmp2)->isDict()) { // media play parameters
-    Object params;
-    if (tmp2.dictLookup("MH", &params)->isDict()) {
+  tmp2 = obj->dictLookup("P");
+  if (tmp2.isDict()) { // media play parameters
+    Object params = tmp2.dictLookup("MH");
+    if (params.isDict()) {
       MH.parseMediaPlayParameters(&params);
     }
-    params.free();
-    if (tmp2.dictLookup("BE", &params)->isDict()) {
+    params = tmp2.dictLookup("BE");
+    if (params.isDict()) {
       BE.parseMediaPlayParameters(&params);
     }
-    params.free();
   } else if (!hasClip) {
     error (errSyntaxError, -1, "Invalid Media Rendition");
     ok = gFalse;
   }
-  tmp2.free();
 
   //
   // parse Media Screen Parameters
-  if (obj->dictLookup("SP", &tmp2)->isDict()) { // media screen parameters
-    Object params;
-    if (tmp2.dictLookup("MH", &params)->isDict()) {
+  tmp2 = obj->dictLookup("SP");
+  if (tmp2.isDict()) { // media screen parameters
+    Object params = tmp2.dictLookup("MH");
+    if (params.isDict()) {
       MH.parseMediaScreenParameters(&params);
     }
-    params.free();
-    if (tmp2.dictLookup("BE", &params)->isDict()) {
+    params = tmp2.dictLookup("BE");
+    if (params.isDict()) {
       BE.parseMediaScreenParameters(&params);
     }
-    params.free();
   }
-  tmp2.free();
+}
+
+MediaRendition::MediaRendition(const MediaRendition &other) {
+  ok = other.ok;
+  MH = other.MH;
+  BE = other.BE;
+  isEmbedded = other.isEmbedded;
+  embeddedStreamObject = other.embeddedStreamObject.copy();
+
+  if (other.contentType)
+    contentType = other.contentType->copy();
+  else
+    contentType = nullptr;
+
+  if (other.fileName)
+    fileName = other.fileName->copy();
+  else
+    fileName = nullptr;
 }
 
 void MediaRendition::outputToFile(FILE* fp) {
   if (!isEmbedded)
     return;
 
-  embeddedStream->reset();
+  embeddedStreamObject.streamReset();
 
   while (1) {
-    int c = embeddedStream->getChar();
+    int c = embeddedStreamObject.streamGetChar();
     if (c == EOF)
       break;
     
@@ -383,19 +371,9 @@
   
 }
 
-MediaRendition *MediaRendition::copy() {
-  // call default copy constructor
-  MediaRendition* new_media = new MediaRendition(*this);
-
-  if (contentType)
-    new_media->contentType = contentType->copy();
-  if (fileName)
-    new_media->fileName = fileName->copy();
-
-  if (new_media->embeddedStream)
-    new_media->embeddedStream->incRef();
-
-  return new_media;
+MediaRendition* MediaRendition::copy()
+{
+  return new MediaRendition(*this);
 }
 
 // TODO: SelectorRendition
diff --git a/poppler/Rendition.h b/poppler/Rendition.h
index 75bfeff..5a937f2 100644
--- a/poppler/Rendition.h
+++ b/poppler/Rendition.h
@@ -5,6 +5,7 @@
 //---------------------------------------------------------------------------------
 // Hugo Mercier <hmercier31[at]gmail.com> (c) 2008
 // Carlos Garcia Campos <carlosgc@gnome.org> (c) 2010
+// Albert Astals Cid <aacid@kde.org> (C) 2017
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License as published by
@@ -118,6 +119,7 @@
 class MediaRendition {
  public:
   MediaRendition(Object *obj);
+  MediaRendition(const MediaRendition &other);
   ~MediaRendition();
 
   GBool isOk () { return ok; }
@@ -129,7 +131,8 @@
   GooString* getFileName() { return fileName; }
 
   GBool getIsEmbedded() { return isEmbedded; }
-  Stream* getEmbbededStream() { return embeddedStream; }
+  Stream* getEmbbededStream() { return isEmbedded ? embeddedStreamObject.getStream() : nullptr; }
+  Object* getEmbbededStreamObject() { return isEmbedded ? &embeddedStreamObject : nullptr; }
   // write embedded stream to file
   void outputToFile(FILE*);
 
@@ -148,7 +151,7 @@
   GooString* contentType;
 
   // if it's embedded
-  Stream* embeddedStream;
+  Object embeddedStreamObject;
 
   // if it's not embedded
   GooString* fileName;
diff --git a/poppler/SecurityHandler.cc b/poppler/SecurityHandler.cc
index 9e0546e..f774ce8 100644
--- a/poppler/SecurityHandler.cc
+++ b/poppler/SecurityHandler.cc
@@ -13,7 +13,7 @@
 // All changes made under the Poppler project to this file are licensed
 // under GPL version 2 or later
 //
-// Copyright (C) 2010, 2012, 2015 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2010, 2012, 2015, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
 // Copyright (C) 2014 Fabio D'Urso <fabiodurso@hotmail.it>
 // Copyright (C) 2016 Alok Anand <alok4nand@gmail.com>
@@ -46,13 +46,12 @@
 //------------------------------------------------------------------------
 
 SecurityHandler *SecurityHandler::make(PDFDoc *docA, Object *encryptDictA) {
-  Object filterObj;
   SecurityHandler *secHdlr;
 #ifdef ENABLE_PLUGINS
   XpdfSecurityHandler *xsh;
 #endif
 
-  encryptDictA->dictLookup("Filter", &filterObj);
+  Object filterObj = encryptDictA->dictLookup("Filter");
   if (filterObj.isName("Standard")) {
     secHdlr = new StandardSecurityHandler(docA, encryptDictA);
   } else if (filterObj.isName()) {
@@ -72,7 +71,6 @@
 	  "Missing or invalid 'Filter' entry in encryption dictionary");
     secHdlr = NULL;
   }
-  filterObj.free();
   return secHdlr;
 }
 
@@ -147,13 +145,6 @@
 						 Object *encryptDictA):
   SecurityHandler(docA)
 {
-  Object versionObj, revisionObj, lengthObj;
-  Object ownerKeyObj, userKeyObj, ownerEncObj, userEncObj;
-  Object permObj, fileIDObj, fileIDObj1;
-  Object cryptFiltersObj, streamFilterObj, stringFilterObj;
-  Object cryptFilterObj, cfmObj, cfLengthObj;
-  Object encryptMetadataObj;
-
   ok = gFalse;
   fileID = NULL;
   ownerKey = NULL;
@@ -162,21 +153,20 @@
   userEnc = NULL;
   fileKeyLength = 0;
 
-  encryptDictA->dictLookup("V", &versionObj);
-  encryptDictA->dictLookup("R", &revisionObj);
-  encryptDictA->dictLookup("Length", &lengthObj);
-  encryptDictA->dictLookup("O", &ownerKeyObj);
-  encryptDictA->dictLookup("U", &userKeyObj);
-  encryptDictA->dictLookup("OE", &ownerEncObj);
-  encryptDictA->dictLookup("UE", &userEncObj);
-  encryptDictA->dictLookup("P", &permObj);
+  Object versionObj = encryptDictA->dictLookup("V");
+  Object revisionObj = encryptDictA->dictLookup("R");
+  Object lengthObj = encryptDictA->dictLookup("Length");
+  Object ownerKeyObj = encryptDictA->dictLookup("O");
+  Object userKeyObj = encryptDictA->dictLookup("U");
+  Object ownerEncObj = encryptDictA->dictLookup("OE");
+  Object userEncObj = encryptDictA->dictLookup("UE");
+  Object permObj = encryptDictA->dictLookup("P");
   if (permObj.isInt64()) {
       unsigned int permUint = permObj.getInt64();
       int perms = permUint - UINT_MAX - 1;
-      permObj.free();
-      permObj.initInt(perms);
+      permObj = Object(perms);
   }
-  doc->getXRef()->getTrailerDict()->dictLookup("ID", &fileIDObj);
+  Object fileIDObj = doc->getXRef()->getTrailerDict()->dictLookup("ID");
   if (versionObj.isInt() &&
       revisionObj.isInt() &&
       permObj.isInt() &&
@@ -210,9 +200,9 @@
       //~ same)
       if ((encVersion == 4 || encVersion == 5) &&
 	  (encRevision == 4 || encRevision == 5 || encRevision == 6)) {
-	encryptDictA->dictLookup("CF", &cryptFiltersObj);
-	encryptDictA->dictLookup("StmF", &streamFilterObj);
-	encryptDictA->dictLookup("StrF", &stringFilterObj);
+	Object cryptFiltersObj = encryptDictA->dictLookup("CF");
+	Object streamFilterObj = encryptDictA->dictLookup("StmF");
+	Object stringFilterObj = encryptDictA->dictLookup("StrF");
 	if (cryptFiltersObj.isDict() &&
 	    streamFilterObj.isName() &&
 	    stringFilterObj.isName() &&
@@ -221,52 +211,43 @@
 	    // no encryption on streams or strings
 	    encVersion = encRevision = -1;
 	  } else {
-	    if (cryptFiltersObj.dictLookup(streamFilterObj.getName(),
-					   &cryptFilterObj)->isDict()) {
-	      cryptFilterObj.dictLookup("CFM", &cfmObj);
+	    Object cryptFilterObj = cryptFiltersObj.dictLookup(streamFilterObj.getName());
+	    if (cryptFilterObj.isDict()) {
+	      Object cfmObj = cryptFilterObj.dictLookup("CFM");
 	      if (cfmObj.isName("V2")) {
 		encVersion = 2;
 		encRevision = 3;
-		if (cryptFilterObj.dictLookup("Length",
-					      &cfLengthObj)->isInt()) {
+		Object cfLengthObj = cryptFilterObj.dictLookup("Length");
+		if (cfLengthObj.isInt()) {
 		  //~ according to the spec, this should be cfLengthObj / 8
 		  fileKeyLength = cfLengthObj.getInt();
 		}
-		cfLengthObj.free();
 	      } else if (cfmObj.isName("AESV2")) {
 		encVersion = 2;
 		encRevision = 3;
 		encAlgorithm = cryptAES;
-		if (cryptFilterObj.dictLookup("Length",
-					      &cfLengthObj)->isInt()) {
+		Object cfLengthObj = cryptFilterObj.dictLookup("Length");
+		if (cfLengthObj.isInt()) {
 		  //~ according to the spec, this should be cfLengthObj / 8
 		  fileKeyLength = cfLengthObj.getInt();
 		}
-		cfLengthObj.free();
 	      } else if (cfmObj.isName("AESV3")) {
 		encVersion = 5;
 		// let encRevision be 5 or 6
 		encAlgorithm = cryptAES256;
-		if (cryptFilterObj.dictLookup("Length",
-					      &cfLengthObj)->isInt()) {
+		Object cfLengthObj = cryptFilterObj.dictLookup("Length");
+		if (cfLengthObj.isInt()) {
 		  //~ according to the spec, this should be cfLengthObj / 8
 		  fileKeyLength = cfLengthObj.getInt();
 		}
-		cfLengthObj.free();
 	      }
-	      cfmObj.free();
 	    }
-	    cryptFilterObj.free();
 	  }
 	}
-	stringFilterObj.free();
-	streamFilterObj.free();
-	cryptFiltersObj.free();
-	if (encryptDictA->dictLookup("EncryptMetadata",
-				     &encryptMetadataObj)->isBool()) {
+	Object encryptMetadataObj = encryptDictA->dictLookup("EncryptMetadata");
+	if (encryptMetadataObj.isBool()) {
 	  encryptMetadata = encryptMetadataObj.getBool();
 	}
-	encryptMetadataObj.free();
       }
       permFlags = permObj.getInt();
       ownerKey = ownerKeyObj.getString()->copy();
@@ -274,12 +255,12 @@
       if (encVersion >= 1 && encVersion <= 2 &&
 	  encRevision >= 2 && encRevision <= 3) {
 	if (fileIDObj.isArray()) {
-	  if (fileIDObj.arrayGet(0, &fileIDObj1)->isString()) {
+	  Object fileIDObj1 = fileIDObj.arrayGet(0);
+	  if (fileIDObj1.isString()) {
 	    fileID = fileIDObj1.getString()->copy();
 	  } else {
 	    fileID = new GooString();
 	  }
-	  fileIDObj1.free();
 	} else {
 	  fileID = new GooString();
 	}
@@ -310,15 +291,6 @@
   } else {
     error(errSyntaxError, -1, "Weird encryption info");
   }
-  fileIDObj.free();
-  permObj.free();
-  userEncObj.free();
-  ownerEncObj.free();
-  userKeyObj.free();
-  ownerKeyObj.free();
-  lengthObj.free();
-  revisionObj.free();
-  versionObj.free();
 }
 
 StandardSecurityHandler::~StandardSecurityHandler() {
@@ -408,7 +380,6 @@
 
 ExternalSecurityHandler::~ExternalSecurityHandler() {
   (*xsh->freeDoc)(xsh->handlerData, docData);
-  encryptDict.free();
 }
 
 void *ExternalSecurityHandler::makeAuthData(GooString *ownerPassword,
diff --git a/poppler/Sound.cc b/poppler/Sound.cc
index 6129fdc..c0dd6cc 100644
--- a/poppler/Sound.cc
+++ b/poppler/Sound.cc
@@ -1,6 +1,6 @@
 /* Sound.cc - an object that holds the sound structure
  * Copyright (C) 2006-2007, Pino Toscano <pino@kde.org>
- * Copyright (C) 2009, Albert Astals Cid <aacid@kde.org>
+ * Copyright (C) 2009, 2017, Albert Astals Cid <aacid@kde.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -38,21 +38,18 @@
   Dict *dict = str->getDict();
   if (dict == NULL)
     return NULL;
-  Object tmp;
   // the Dict must have the 'R' key of type num
-  dict->lookup("R", &tmp);
+  Object tmp = dict->lookup("R");
   if (tmp.isNum()) {
     return new Sound(obj);
   } else {
-    return NULL;
+    return nullptr;
   }
 }
 
 Sound::Sound(Object *obj, bool readAttrs)
 {
-  streamObj = new Object();
-  streamObj->initNull();
-  obj->copy(streamObj);
+  streamObj = obj->copy();
 
   fileName = NULL;
   samplingRate = 0.0;
@@ -62,43 +59,37 @@
 
   if (readAttrs)
   {
-    Object tmp;
-    Dict *dict = streamObj->getStream()->getDict();
-    dict->lookup("F", &tmp);
+    Dict *dict = streamObj.getStream()->getDict();
+    Object tmp = dict->lookup("F");
     if (!tmp.isNull()) {
-      Object obj1;
       // valid 'F' key -> external file
       kind = soundExternal;
-      if (getFileSpecNameForPlatform (&tmp, &obj1)) {
+      Object obj1 = getFileSpecNameForPlatform (&tmp);
+      if (obj1.isString()) {
         fileName = obj1.getString()->copy();
-        obj1.free();
       }
     } else {
       // no file specification, then the sound data have to be
       // extracted from the stream
       kind = soundEmbedded;
     }
-    tmp.free();
     // sampling rate
-    dict->lookup("R", &tmp);
+    tmp = dict->lookup("R");
     if (tmp.isNum()) {
       samplingRate = tmp.getNum();
     }
-    tmp.free();
     // sound channels
-    dict->lookup("C", &tmp);
+    tmp = dict->lookup("C");
     if (tmp.isInt()) {
       channels = tmp.getInt();
     }
-    tmp.free();
     // bits per sample
-    dict->lookup("B", &tmp);
+    tmp = dict->lookup("B");
     if (tmp.isInt()) {
       bitsPerSample = tmp.getInt();
     }
-    tmp.free();
     // encoding format
-    dict->lookup("E", &tmp);
+    tmp = dict->lookup("E");
     if (tmp.isName())
     {
       const char *enc = tmp.getName();
@@ -112,25 +103,22 @@
         encoding = soundALaw;
       }
     }
-    tmp.free();
   }
 }
 
 Sound::~Sound()
 {
   delete fileName;
-  streamObj->free();
-  delete streamObj;
 }
 
 Stream *Sound::getStream()
 {
-  return streamObj->getStream();
+  return streamObj.getStream();
 }
 
 Sound *Sound::copy()
 {
-  Sound *newsound = new Sound(streamObj, false);
+  Sound *newsound = new Sound(&streamObj, false);
 
   newsound->kind = kind;
   if (fileName) {
diff --git a/poppler/Sound.h b/poppler/Sound.h
index acb0f8d..5e33cb5 100644
--- a/poppler/Sound.h
+++ b/poppler/Sound.h
@@ -1,5 +1,6 @@
 /* Sound.h - an object that holds the sound structure
  * Copyright (C) 2006-2007, Pino Toscano <pino@kde.org>
+ * Copyright (C) 2017, Albert Astals Cid <aacid@kde.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -46,7 +47,7 @@
   // Destructor
   ~Sound();
 
-  Object *getObject() { return streamObj; }
+  Object *getObject() { return &streamObj; }
   Stream *getStream();
 
   SoundKind getSoundKind() { return kind; }
@@ -62,7 +63,7 @@
   // Create a sound. The Object obj is ensured to be a Stream with a Dict
   Sound(Object *obj, bool readAttrs = true);
 
-  Object *streamObj;
+  Object streamObj;
   SoundKind kind;
   GooString *fileName;
   double samplingRate;
diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc
index 5502be6..60edb8a 100644
--- a/poppler/SplashOutputDev.cc
+++ b/poppler/SplashOutputDev.cc
@@ -2076,8 +2076,10 @@
   delete id;
   delete fontLoc;
   fontLoc = NULL;
-  if (fontsrc && !fontsrc->isFile)
+  if (fontsrc && !fontsrc->isFile) {
       fontsrc->unref();
+      fontsrc = nullptr;
+  }
 
   id = new SplashOutFontFileID(gfxFont->getID());
   if ((fontFile = fontEngine->getFontFile(id))) {
@@ -3798,7 +3800,7 @@
 				      int maskHeight, GBool maskInvert,
 				      GBool maskInterpolate) {
   GfxImageColorMap *maskColorMap;
-  Object maskDecode, decodeLow, decodeHigh;
+  Object decodeLow, decodeHigh;
   double *ctm;
   SplashCoord mat[6];
   SplashOutMaskedImageData imgData;
@@ -3825,14 +3827,11 @@
   // If the mask is higher resolution than the image, use
   // drawSoftMaskedImage() instead.
   if (maskWidth > width || maskHeight > height) {
-    decodeLow.initInt(maskInvert ? 0 : 1);
-    decodeHigh.initInt(maskInvert ? 1 : 0);
-    maskDecode.initArray((xref) ? xref : doc->getXRef());
-    maskDecode.arrayAdd(&decodeLow);
-    maskDecode.arrayAdd(&decodeHigh);
+    Object maskDecode(new Array((xref) ? xref : doc->getXRef()));
+    maskDecode.arrayAdd(Object(maskInvert ? 0 : 1));
+    maskDecode.arrayAdd(Object(maskInvert ? 1 : 0));
     maskColorMap = new GfxImageColorMap(1, &maskDecode,
 					new GfxDeviceGrayColorSpace());
-    maskDecode.free();
     drawSoftMaskedImage(state, ref, str, width, height, colorMap, interpolate,
 			maskStr, maskWidth, maskHeight, maskColorMap, maskInterpolate);
     delete maskColorMap;
@@ -4021,9 +4020,7 @@
     maskStr->reset();
     maskStr->doGetChars(maskWidth * maskHeight, data);
     maskStr->close();
-    Object maskDict;
-    maskDict.initDict(maskStr->getDict());
-    maskStr = new MemStream((char *)data, 0, maskWidth * maskHeight, &maskDict);
+    maskStr = new MemStream((char *)data, 0, maskWidth * maskHeight, maskStr->getDictObject()->copy());
     ((MemStream *) maskStr)->setNeedFree(gTrue);
   }
   imgMaskData.imgStr = new ImageStream(maskStr, maskWidth,
diff --git a/poppler/StdinPDFDocBuilder.cc b/poppler/StdinPDFDocBuilder.cc
index 571ee46..f4aa12c 100644
--- a/poppler/StdinPDFDocBuilder.cc
+++ b/poppler/StdinPDFDocBuilder.cc
@@ -5,7 +5,7 @@
 // This file is licensed under the GPLv2 or later
 //
 // Copyright 2010 Hib Eris <hib@hiberis.nl>
-// Copyright 2010 Albert Astals Cid <aacid@kde.org>
+// Copyright 2010, 2017 Albert Astals Cid <aacid@kde.org>
 //
 //========================================================================
 
@@ -23,12 +23,9 @@
 StdinPDFDocBuilder::buildPDFDoc(const GooString &uri, GooString *ownerPassword,
                                     GooString *userPassword, void *guiDataA)
 {
-  Object obj;
-
-  obj.initNull();
   CachedFile *cachedFile = new CachedFile(new StdinCacheLoader(), NULL);
   return new PDFDoc(new CachedFileStream(cachedFile, 0, gFalse,
-                                         cachedFile->getLength(), &obj),
+                                         cachedFile->getLength(), Object(objNull)),
                     ownerPassword, userPassword);
 }
 
diff --git a/poppler/Stream.cc b/poppler/Stream.cc
index 606902f..df76765 100644
--- a/poppler/Stream.cc
+++ b/poppler/Stream.cc
@@ -169,51 +169,45 @@
   return new GooString();
 }
 
-Stream *Stream::addFilters(Object *dict, int recursion) {
+Stream *Stream::addFilters(Dict *dict, int recursion) {
   Object obj, obj2;
   Object params, params2;
   Stream *str;
   int i;
 
   str = this;
-  dict->dictLookup("Filter", &obj, recursion);
+  obj = dict->lookup("Filter", recursion);
   if (obj.isNull()) {
-    obj.free();
-    dict->dictLookup("F", &obj, recursion);
+    obj = dict->lookup("F", recursion);
   }
-  dict->dictLookup("DecodeParms", &params, recursion);
+  params = dict->lookup("DecodeParms", recursion);
   if (params.isNull()) {
-    params.free();
-    dict->dictLookup("DP", &params, recursion);
+    params = dict->lookup("DP", recursion);
   }
   if (obj.isName()) {
     str = makeFilter(obj.getName(), str, &params, recursion, dict);
   } else if (obj.isArray()) {
     for (i = 0; i < obj.arrayGetLength(); ++i) {
-      obj.arrayGet(i, &obj2, recursion);
+      obj2 = obj.arrayGet(i, recursion);
       if (params.isArray())
-	params.arrayGet(i, &params2, recursion);
+	params2 = params.arrayGet(i, recursion);
       else
-	params2.initNull();
+	params2.setToNull();
       if (obj2.isName()) {
 	str = makeFilter(obj2.getName(), str, &params2, recursion);
       } else {
 	error(errSyntaxError, getPos(), "Bad filter name");
 	str = new EOFStream(str);
       }
-      obj2.free();
-      params2.free();
     }
   } else if (!obj.isNull()) {
     error(errSyntaxError, getPos(), "Bad 'Filter' attribute in stream");
   }
-  obj.free();
-  params.free();
 
   return str;
 }
 
-Stream *Stream::makeFilter(char *name, Stream *str, Object *params, int recursion, Object *dict) {
+Stream *Stream::makeFilter(char *name, Stream *str, Object *params, int recursion, Dict *dict) {
   int pred;			// parameters
   int colors;
   int bits;
@@ -234,26 +228,21 @@
     bits = 8;
     early = 1;
     if (params->isDict()) {
-      params->dictLookup("Predictor", &obj, recursion);
+      obj = params->dictLookup("Predictor", recursion);
       if (obj.isInt())
 	pred = obj.getInt();
-      obj.free();
-      params->dictLookup("Columns", &obj, recursion);
+      obj = params->dictLookup("Columns", recursion);
       if (obj.isInt())
 	columns = obj.getInt();
-      obj.free();
-      params->dictLookup("Colors", &obj, recursion);
+      obj = params->dictLookup("Colors", recursion);
       if (obj.isInt())
 	colors = obj.getInt();
-      obj.free();
-      params->dictLookup("BitsPerComponent", &obj, recursion);
+      obj = params->dictLookup("BitsPerComponent", recursion);
       if (obj.isInt())
 	bits = obj.getInt();
-      obj.free();
-      params->dictLookup("EarlyChange", &obj, recursion);
+      obj = params->dictLookup("EarlyChange", recursion);
       if (obj.isInt())
 	early = obj.getInt();
-      obj.free();
     }
     str = new LZWStream(str, pred, columns, colors, bits, early);
   } else if (!strcmp(name, "RunLengthDecode") || !strcmp(name, "RL")) {
@@ -267,41 +256,34 @@
     endOfBlock = gTrue;
     black = gFalse;
     if (params->isDict()) {
-      params->dictLookup("K", &obj, recursion);
+      obj = params->dictLookup("K", recursion);
       if (obj.isInt()) {
 	encoding = obj.getInt();
       }
-      obj.free();
-      params->dictLookup("EndOfLine", &obj, recursion);
+      obj = params->dictLookup("EndOfLine", recursion);
       if (obj.isBool()) {
 	endOfLine = obj.getBool();
       }
-      obj.free();
-      params->dictLookup("EncodedByteAlign", &obj, recursion);
+      obj = params->dictLookup("EncodedByteAlign", recursion);
       if (obj.isBool()) {
 	byteAlign = obj.getBool();
       }
-      obj.free();
-      params->dictLookup("Columns", &obj, recursion);
+      obj = params->dictLookup("Columns", recursion);
       if (obj.isInt()) {
 	columns = obj.getInt();
       }
-      obj.free();
-      params->dictLookup("Rows", &obj, recursion);
+      obj = params->dictLookup("Rows", recursion);
       if (obj.isInt()) {
 	rows = obj.getInt();
       }
-      obj.free();
-      params->dictLookup("EndOfBlock", &obj, recursion);
+      obj = params->dictLookup("EndOfBlock", recursion);
       if (obj.isBool()) {
 	endOfBlock = obj.getBool();
       }
-      obj.free();
-      params->dictLookup("BlackIs1", &obj, recursion);
+      obj = params->dictLookup("BlackIs1", recursion);
       if (obj.isBool()) {
 	black = obj.getBool();
       }
-      obj.free();
     }
     str = new CCITTFaxStream(str, encoding, endOfLine, byteAlign,
 			     columns, rows, endOfBlock, black);
@@ -309,10 +291,10 @@
 #if HAVE_DCT_DECODER
     int colorXform = -1;
     if (params->isDict()) {
-      if (params->dictLookup("ColorTransform", &obj, recursion)->isInt()) {
+      obj = params->dictLookup("ColorTransform", recursion);
+      if (obj.isInt()) {
 	colorXform = obj.getInt();
       }
-      obj.free();
     }
     str = new DCTStream(str, colorXform, dict, recursion);
 #else
@@ -325,33 +307,27 @@
     colors = 1;
     bits = 8;
     if (params->isDict()) {
-      params->dictLookup("Predictor", &obj, recursion);
+      obj = params->dictLookup("Predictor", recursion);
       if (obj.isInt())
 	pred = obj.getInt();
-      obj.free();
-      params->dictLookup("Columns", &obj, recursion);
+      obj = params->dictLookup("Columns", recursion);
       if (obj.isInt())
 	columns = obj.getInt();
-      obj.free();
-      params->dictLookup("Colors", &obj, recursion);
+      obj = params->dictLookup("Colors", recursion);
       if (obj.isInt())
 	colors = obj.getInt();
-      obj.free();
-      params->dictLookup("BitsPerComponent", &obj, recursion);
+      obj = params->dictLookup("BitsPerComponent", recursion);
       if (obj.isInt())
 	bits = obj.getInt();
-      obj.free();
     }
     str = new FlateStream(str, pred, columns, colors, bits);
   } else if (!strcmp(name, "JBIG2Decode")) {
     if (params->isDict()) {
       XRef *xref = params->getDict()->getXRef();
-      params->dictLookupNF("JBIG2Globals", &obj);
-      obj.fetch(xref, &globals, recursion);
+      obj = params->dictLookupNF("JBIG2Globals");
+      globals = obj.fetch(xref, recursion);
     }
     str = new JBIG2Stream(str, &globals, &obj);
-    globals.free();
-    obj.free();
   } else if (!strcmp(name, "JPXDecode")) {
 #ifdef HAVE_JPX_DECODER
     str = new JPXStream(str);
@@ -377,7 +353,6 @@
 //------------------------------------------------------------------------
 OutStream::OutStream ()
 {
-  ref = 1;
 }
 
 OutStream::~OutStream ()
@@ -426,13 +401,12 @@
 // BaseStream
 //------------------------------------------------------------------------
 
-BaseStream::BaseStream(Object *dictA, Goffset lengthA) {
-  dict = *dictA;
+BaseStream::BaseStream(Object &&dictA, Goffset lengthA) {
+  dict = std::move(dictA);
   length = lengthA;
 }
 
 BaseStream::~BaseStream() {
-  dict.free();
 }
 
 //------------------------------------------------------------------------
@@ -781,8 +755,8 @@
 //------------------------------------------------------------------------
 
 FileStream::FileStream(GooFile* fileA, Goffset startA, GBool limitedA,
-		       Goffset lengthA, Object *dictA):
-    BaseStream(dictA, lengthA) {
+		       Goffset lengthA, Object &&dictA):
+    BaseStream(std::move(dictA), lengthA) {
   file = fileA;
   offset = start = startA;
   limited = limitedA;
@@ -798,12 +772,12 @@
 }
 
 BaseStream *FileStream::copy() {
-  return new FileStream(file, start, limited, length, &dict);
+  return new FileStream(file, start, limited, length, dict.copy());
 }
 
 Stream *FileStream::makeSubStream(Goffset startA, GBool limitedA,
-				  Goffset lengthA, Object *dictA) {
-  return new FileStream(file, startA, limitedA, lengthA, dictA);
+				  Goffset lengthA, Object &&dictA) {
+  return new FileStream(file, startA, limitedA, lengthA, std::move(dictA));
 }
 
 void FileStream::reset() {
@@ -872,8 +846,8 @@
 //------------------------------------------------------------------------
 
 CachedFileStream::CachedFileStream(CachedFile *ccA, Goffset startA,
-        GBool limitedA, Goffset lengthA, Object *dictA)
-  : BaseStream(dictA, lengthA)
+        GBool limitedA, Goffset lengthA, Object &&dictA)
+  : BaseStream(std::move(dictA), lengthA)
 {
   cc = ccA;
   start = startA;
@@ -893,14 +867,14 @@
 
 BaseStream *CachedFileStream::copy() {
   cc->incRefCnt();
-  return new CachedFileStream(cc, start, limited, length, &dict);
+  return new CachedFileStream(cc, start, limited, length, dict.copy());
 }
 
 Stream *CachedFileStream::makeSubStream(Goffset startA, GBool limitedA,
-        Goffset lengthA, Object *dictA)
+        Goffset lengthA, Object &&dictA)
 {
   cc->incRefCnt();
-  return new CachedFileStream(cc, startA, limitedA, lengthA, dictA);
+  return new CachedFileStream(cc, startA, limitedA, lengthA, std::move(dictA));
 }
 
 void CachedFileStream::reset()
@@ -975,8 +949,8 @@
 // MemStream
 //------------------------------------------------------------------------
 
-MemStream::MemStream(char *bufA, Goffset startA, Goffset lengthA, Object *dictA):
-    BaseStream(dictA, lengthA) {
+MemStream::MemStream(char *bufA, Goffset startA, Goffset lengthA, Object &&dictA):
+    BaseStream(std::move(dictA), lengthA) {
   buf = bufA;
   start = startA;
   length = lengthA;
@@ -992,11 +966,11 @@
 }
 
 BaseStream *MemStream::copy() {
-  return new MemStream(buf, start, length, &dict);
+  return new MemStream(buf, start, length, dict.copy());
 }
 
 Stream *MemStream::makeSubStream(Goffset startA, GBool limited,
-				 Goffset lengthA, Object *dictA) {
+				 Goffset lengthA, Object &&dictA) {
   MemStream *subStr;
   Goffset newLength;
 
@@ -1005,7 +979,7 @@
   } else {
     newLength = lengthA;
   }
-  subStr = new MemStream(buf, startA, newLength, dictA);
+  subStr = new MemStream(buf, startA, newLength, std::move(dictA));
   return subStr;
 }
 
@@ -1058,9 +1032,9 @@
 // EmbedStream
 //------------------------------------------------------------------------
 
-EmbedStream::EmbedStream(Stream *strA, Object *dictA,
+EmbedStream::EmbedStream(Stream *strA, Object &&dictA,
 			 GBool limitedA, Goffset lengthA):
-    BaseStream(dictA, lengthA) {
+    BaseStream(std::move(dictA), lengthA) {
   str = strA;
   limited = limitedA;
   length = lengthA;
@@ -1075,7 +1049,7 @@
 }
 
 Stream *EmbedStream::makeSubStream(Goffset start, GBool limitedA,
-				   Goffset lengthA, Object *dictA) {
+				   Goffset lengthA, Object &&dictA) {
   error(errInternal, -1, "Called makeSubStream() on EmbedStream");
   return NULL;
 }
@@ -2445,7 +2419,7 @@
   63
 };
 
-DCTStream::DCTStream(Stream *strA, int colorXformA, Object *dict, int recursion):
+DCTStream::DCTStream(Stream *strA, int colorXformA, Dict *dict, int recursion):
     FilterStream(strA) {
   int i, j;
 
diff --git a/poppler/Stream.h b/poppler/Stream.h
index f3cf38b..2317080 100644
--- a/poppler/Stream.h
+++ b/poppler/Stream.h
@@ -15,7 +15,7 @@
 //
 // Copyright (C) 2005 Jeff Muizelaar <jeff@infidigm.net>
 // Copyright (C) 2008 Julien Rebetez <julien@fhtagn.net>
-// Copyright (C) 2008, 2010, 2011, 2016 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2008, 2010, 2011, 2016, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
 // Copyright (C) 2009 Stefan Thomas <thomas@eload24.com>
 // Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
@@ -105,10 +105,6 @@
   // Destructor.
   virtual ~Stream();
 
-  // Reference counting.
-  int incRef();
-  int decRef();
-
   // Get kind of stream.
   virtual StreamKind getKind() = 0;
 
@@ -213,6 +209,7 @@
 
   // Get the dictionary associated with this stream.
   virtual Dict *getDict() = 0;
+  virtual Object *getDictObject() = 0;
 
   // Is this an encoding filter?
   virtual GBool isEncoder() { return gFalse; }
@@ -226,13 +223,19 @@
 
   // Add filters to this stream according to the parameters in <dict>.
   // Returns the new stream.
-  Stream *addFilters(Object *dict, int recursion = 0);
+  Stream *addFilters(Dict *dict, int recursion = 0);
 
 private:
+  friend class Object; // for incRef/decRef
+
+  // Reference counting.
+  int incRef();
+  int decRef();
+
   virtual GBool hasGetChars() { return false; }
   virtual int getChars(int nChars, Guchar *buffer);
 
-  Stream *makeFilter(char *name, Stream *str, Object *params, int recursion = 0, Object *dict = NULL);
+  Stream *makeFilter(char *name, Stream *str, Object *params, int recursion = 0, Dict *dict = nullptr);
 
   int ref;			// reference count
 #if MULTITHREADED
@@ -254,10 +257,6 @@
   // Desctructor.
   virtual ~OutStream ();
 
-  // Reference counting.
-  int incRef() { return ++ref; }
-  int decRef() { return --ref; }
-
   // Close the stream
   virtual void close() = 0;
 
@@ -268,10 +267,6 @@
   virtual void put (char c) = 0;
 
   virtual void printf (const char *format, ...) GCC_PRINTF_FORMAT(2,3) = 0;
-
-private:
-  int ref; // reference count
-    
 };
 
 //------------------------------------------------------------------------
@@ -306,16 +301,18 @@
 class BaseStream: public Stream {
 public:
 
-  BaseStream(Object *dictA, Goffset lengthA);
+    // TODO Mirar si puedo hacer que dictA sea un puntero
+  BaseStream(Object &&dictA, Goffset lengthA);
   ~BaseStream();
   virtual BaseStream *copy() = 0;
   virtual Stream *makeSubStream(Goffset start, GBool limited,
-				Goffset length, Object *dict) = 0;
+				Goffset length, Object &&dict) = 0;
   void setPos(Goffset pos, int dir = 0) override = 0;
   GBool isBinary(GBool last = gTrue) override { return last; }
   BaseStream *getBaseStream() override { return this; }
   Stream *getUndecodedStream() override { return this; }
   Dict *getDict() override { return dict.getDict(); }
+  Object *getDictObject() override { return &dict; }
   virtual GooString *getFileName() { return NULL; }
   virtual Goffset getLength() { return length; }
 
@@ -346,6 +343,7 @@
   BaseStream *getBaseStream() override { return str->getBaseStream(); }
   Stream *getUndecodedStream() override { return str->getUndecodedStream(); }
   Dict *getDict() override { return str->getDict(); }
+  Object *getDictObject() override { return str->getDictObject(); }
   Stream *getNextStream() override { return str; }
 
   int getUnfilteredChar () override { return str->getUnfilteredChar(); }
@@ -447,11 +445,11 @@
 public:
 
   FileStream(GooFile* fileA, Goffset startA, GBool limitedA,
-	     Goffset lengthA, Object *dictA);
+	     Goffset lengthA, Object &&dictA);
   ~FileStream();
   BaseStream *copy() override;
   Stream *makeSubStream(Goffset startA, GBool limitedA,
-				Goffset lengthA, Object *dictA) override;
+				Goffset lengthA, Object &&dictA) override;
   StreamKind getKind() override { return strFile; }
   void reset() override;
   void close() override;
@@ -517,11 +515,11 @@
 public:
 
   CachedFileStream(CachedFile *ccA, Goffset startA, GBool limitedA,
-	     Goffset lengthA, Object *dictA);
+	     Goffset lengthA, Object &&dictA);
   ~CachedFileStream();
   BaseStream *copy() override;
   Stream *makeSubStream(Goffset startA, GBool limitedA,
-				Goffset lengthA, Object *dictA) override;
+				Goffset lengthA, Object &&dictA) override;
   StreamKind getKind() override { return strCachedFile; }
   void reset() override;
   void close() override;
@@ -560,11 +558,11 @@
 class MemStream: public BaseStream {
 public:
 
-  MemStream(char *bufA, Goffset startA, Goffset lengthA, Object *dictA);
+  MemStream(char *bufA, Goffset startA, Goffset lengthA, Object &&dictA);
   ~MemStream();
   BaseStream *copy() override;
   Stream *makeSubStream(Goffset start, GBool limited,
-				Goffset lengthA, Object *dictA) override;
+				Goffset lengthA, Object &&dictA) override;
   StreamKind getKind() override { return strWeird; }
   void reset() override;
   void close() override;
@@ -609,11 +607,11 @@
 class EmbedStream: public BaseStream {
 public:
 
-  EmbedStream(Stream *strA, Object *dictA, GBool limitedA, Goffset lengthA);
+  EmbedStream(Stream *strA, Object &&dictA, GBool limitedA, Goffset lengthA);
   ~EmbedStream();
   BaseStream *copy() override;
   Stream *makeSubStream(Goffset start, GBool limitedA,
-				Goffset lengthA, Object *dictA) override;
+				Goffset lengthA, Object &&dictA) override;
   StreamKind getKind() override { return str->getKind(); }
   void reset() override {}
   int getChar() override;
@@ -868,7 +866,7 @@
 class DCTStream: public FilterStream {
 public:
 
-  DCTStream(Stream *strA, int colorXformA, Object *dict, int recursion);
+  DCTStream(Stream *strA, int colorXformA, Dict *dict, int recursion);
   virtual ~DCTStream();
   StreamKind getKind() override { return strDCT; }
   void reset() override;
diff --git a/poppler/StructElement.cc b/poppler/StructElement.cc
index c668820..0fbd336 100644
--- a/poppler/StructElement.cc
+++ b/poppler/StructElement.cc
@@ -6,7 +6,7 @@
 //
 // Copyright 2013, 2014 Igalia S.L.
 // Copyright 2014 Luigi Scarso <luigi.scarso@gmail.com>
-// Copyright 2014 Albert Astals Cid <aacid@kde.org>
+// Copyright 2014, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright 2015 Dmytro Morgun <lztoad@gmail.com>
 //
 //========================================================================
@@ -170,18 +170,15 @@
 
   GBool okay = gTrue;
   for (int i = 0; i < 3; i++) {
-    Object obj;
-    if (!value->arrayGet(i, &obj)->isNum()) {
+    Object obj = value->arrayGet(i);
+    if (!obj.isNum()) {
       okay = gFalse;
-      obj.free();
       break;
     }
     if (obj.getNum() < 0.0 || obj.getNum() > 1.0) {
       okay = gFalse;
-      obj.free();
       break;
     }
-    obj.free();
   }
 
   return okay;
@@ -220,14 +217,11 @@
                                                                         \
       GBool okay = gTrue;                                               \
       for (int i = 0; i < value->arrayGetLength(); i++) {               \
-        Object obj;                                                     \
-        value->arrayGet(i, &obj);                                       \
+        Object obj = value->arrayGet(i);                                \
         if ((!allowNulls && obj.isNull()) || !checkItem(&obj)) {        \
           okay = gFalse;                                                \
-          obj.free();                                                   \
           break;                                                        \
         }                                                               \
-        obj.free();                                                     \
       }                                                                 \
       return okay;                                                      \
     }
@@ -254,46 +248,17 @@
 };
 
 struct AttributeDefaults {
-  Object Inline;
-  Object LrTb;
-  Object Normal;
-  Object Distribute;
-  Object off;
-  Object Zero;
-  Object Auto;
-  Object Start;
-  Object None;
-  Object Before;
-  Object Nat1;
-
-  AttributeDefaults() {
-    Inline.initName("Inline");
-    LrTb.initName("LrTb");
-    Normal.initName("Normal");
-    Distribute.initName("Distribute");
-    off.initName("off");
-
-    Zero.initReal(0.0);
-    Auto.initName("Auto");
-    Start.initName("Start");
-    None.initName("None");
-    Before.initName("Before");
-    Nat1.initInt(1);
-  }
-
-  ~AttributeDefaults() {
-    Inline.free();
-    LrTb.free();
-    Normal.free();
-    Distribute.free();
-    off.free();
-    Zero.free();
-    Auto.free();
-    Start.free();
-    None.free();
-    Before.free();
-    Nat1.free();
-  }
+  Object Inline  = Object(objName, "Inline");
+  Object LrTb = Object(objName, "LrTb");
+  Object Normal = Object(objName, "Normal");
+  Object Distribute = Object(objName, "Distribute");
+  Object off = Object(objName, "off");
+  Object Zero = Object(0.0);
+  Object Auto = Object(objName, "Auto");
+  Object Start = Object(objName, "Start");
+  Object None = Object(objName, "None");
+  Object Before = Object(objName, "Before");
+  Object Nat1 = Object(1);
 };
 
 static const AttributeDefaults attributeDefaults;
@@ -704,7 +669,7 @@
   formatted(NULL)
 {
   assert(valueA);
-  valueA->copy(&value);
+  value = valueA->copy();
 }
 
 Attribute::Attribute(Type type, Object *valueA):
@@ -718,7 +683,7 @@
 {
   assert(valueA);
 
-  valueA->copy(&value);
+  value = valueA->copy();
 
   if (!checkType())
     type = Unknown;
@@ -727,7 +692,6 @@
 Attribute::~Attribute()
 {
   delete formatted;
-  value.free();
 }
 
 const char *Attribute::getTypeName() const
@@ -805,10 +769,11 @@
 Attribute *Attribute::parseUserProperty(Dict *property)
 {
   Object obj, value;
-  const char *name = NULL;
+  const char *name = nullptr;
   int nameLen = GooString::CALC_STRING_LEN;
 
-  if (property->lookup("N", &obj)->isString()) {
+  obj = property->lookup("N");
+  if (obj.isString()) {
     GooString *s = obj.getString();
     name = s->getCString();
     nameLen = s->getLength();
@@ -816,34 +781,29 @@
     name = obj.getName();
   else {
     error(errSyntaxError, -1, "N object is wrong type ({0:s})", obj.getTypeName());
-    obj.free();
-    return NULL;
+    return nullptr;
   }
 
-  if (property->lookup("V", &value)->isNull()) {
+  value = property->lookup("V");
+  if (value.isNull()) {
     error(errSyntaxError, -1, "V object is wrong type ({0:s})", value.getTypeName());
-    value.free();
-    obj.free();
-    return NULL;
+    return nullptr;
   }
 
   Attribute *attribute = new Attribute(name, nameLen, &value);
-  value.free();
-  obj.free();
-
-  if (property->lookup("F", &obj)->isString()) {
+  obj = property->lookup("F");
+  if (obj.isString()) {
     attribute->setFormattedValue(obj.getString()->getCString());
   } else if (!obj.isNull()) {
     error(errSyntaxWarning, -1, "F object is wrong type ({0:s})", obj.getTypeName());
   }
-  obj.free();
 
-  if (property->lookup("H", &obj)->isBool()) {
+  obj = property->lookup("H");
+  if (obj.isBool()) {
     attribute->setHidden(obj.getBool());
   } else if (!obj.isNull()) {
     error(errSyntaxWarning, -1, "H object is wrong type ({0:s})", obj.getTypeName());
   }
-  obj.free();
 
   return attribute;
 }
@@ -871,7 +831,6 @@
   delete id;
   delete title;
   delete language;
-  parentRef.free();
   for (ElemPtrArray::iterator i = elements.begin(); i != elements.end(); ++i) delete *i;
   for (AttrPtrArray::iterator i = attributes.begin(); i != attributes.end(); ++i) delete *i;
 }
@@ -919,7 +878,6 @@
     delete c;
   else
     delete s;
-  pageRef.free();
 }
 
 GBool StructElement::isBlock() const
@@ -1058,21 +1016,22 @@
   return mcdev.getTextSpans();
 }
 
-static StructElement::Type roleMapResolve(Dict *roleMap, const char *name, const char *curName, Object *resolved)
+static StructElement::Type roleMapResolve(Dict *roleMap, const char *name, const char *curName)
 {
   // Circular reference
   if (curName && !strcmp(name, curName))
     return StructElement::Unknown;
 
-  if (roleMap->lookup(curName ? curName : name, resolved)->isName()) {
-    StructElement::Type type = nameToType(resolved->getName());
+  Object resolved = roleMap->lookup(curName ? curName : name);
+  if (resolved.isName()) {
+    StructElement::Type type = nameToType(resolved.getName());
     return type == StructElement::Unknown
-      ? roleMapResolve(roleMap, name, resolved->getName(), resolved)
+      ? roleMapResolve(roleMap, name, resolved.getName())
       : type;
   }
 
-  if (!resolved->isNull())
-    error(errSyntaxWarning, -1, "RoleMap entry is wrong type ({0:s})", resolved->getTypeName());
+  if (!resolved.isNull())
+    error(errSyntaxWarning, -1, "RoleMap entry is wrong type ({0:s})", resolved.getTypeName());
   return StructElement::Unknown;
 }
 
@@ -1081,31 +1040,30 @@
   Object obj;
 
   // Type is optional, but if present must be StructElem
-  if (!element->lookup("Type", &obj)->isNull() && !obj.isName("StructElem")) {
+  obj = element->lookup("Type");
+  if (!obj.isNull() && !obj.isName("StructElem")) {
     error(errSyntaxError, -1, "Type of StructElem object is wrong");
-    obj.free();
     return;
   }
-  obj.free();
 
   // Parent object reference (required).
-  if (!element->lookupNF("P", &s->parentRef)->isRef()) {
+  s->parentRef = element->lookupNF("P");
+  if (!s->parentRef.isRef()) {
     error(errSyntaxError, -1, "P object is wrong type ({0:s})", obj.getTypeName());
     return;
   }
 
   // Check whether the S-type is valid for the top level
   // element and create a node of the appropriate type.
-  if (!element->lookup("S", &obj)->isName()) {
+  obj = element->lookup("S");
+  if (!obj.isName()) {
     error(errSyntaxError, -1, "S object is wrong type ({0:s})", obj.getTypeName());
-    obj.free();
     return;
   }
 
   // Type name may not be standard, resolve through RoleMap first.
   if (treeRoot->getRoleMap()) {
-    Object resolvedName;
-    type = roleMapResolve(treeRoot->getRoleMap(), obj.getName(), NULL, &resolvedName);
+    type = roleMapResolve(treeRoot->getRoleMap(), obj.getName(), NULL);
   }
 
   // Resolving through RoleMap may leave type as Unknown, e.g. for types
@@ -1116,67 +1074,66 @@
   // At this point either the type name must have been resolved.
   if (type == Unknown) {
     error(errSyntaxError, -1, "StructElem object is wrong type ({0:s})", obj.getName());
-    obj.free();
     return;
   }
-  obj.free();
 
   // Object ID (optional), to be looked at the IDTree in the tree root.
-  if (element->lookup("ID", &obj)->isString()) {
+  obj = element->lookup("ID");
+  if (obj.isString()) {
     s->id = obj.takeString();
   }
-  obj.free();
 
   // Page reference (optional) in which at least one of the child items
   // is to be rendered in. Note: each element stores only the /Pg value
   // contained by it, and StructElement::getPageRef() may look in parent
   // elements to find the page where an element belongs.
-  element->lookupNF("Pg", &pageRef);
+  pageRef = element->lookupNF("Pg");
 
   // Revision number (optional).
-  if (element->lookup("R", &obj)->isInt()) {
+  obj = element->lookup("R");
+  if (obj.isInt()) {
     s->revision = obj.getInt();
   }
-  obj.free();
 
   // Element title (optional).
-  if (element->lookup("T", &obj)->isString()) {
+  obj = element->lookup("T");
+  if (obj.isString()) {
     s->title = obj.takeString();
   }
-  obj.free();
 
   // Language (optional).
-  if (element->lookup("Lang", &obj)->isString()) {
+  obj = element->lookup("Lang");
+  if (obj.isString()) {
     s->language = obj.takeString();
   }
-  obj.free();
 
   // Alternative text (optional).
-  if (element->lookup("Alt", &obj)->isString()) {
+  obj = element->lookup("Alt");
+  if (obj.isString()) {
     s->altText = obj.takeString();
   }
-  obj.free();
 
   // Expanded form of an abbreviation (optional).
-  if (element->lookup("E", &obj)->isString()) {
+  obj = element->lookup("E");
+  if (obj.isString()) {
     s->expandedAbbr = obj.takeString();
   }
-  obj.free();
 
   // Actual text (optional).
-  if (element->lookup("ActualText", &obj)->isString()) {
+  obj = element->lookup("ActualText");
+  if (obj.isString()) {
     s->actualText = obj.takeString();
   }
-  obj.free();
 
   // Attributes directly attached to the element (optional).
-  if (element->lookup("A", &obj)->isDict()) {
+  obj = element->lookup("A");
+  if (obj.isDict()) {
     parseAttributes(obj.getDict());
   } else if (obj.isArray()) {
-    Object iobj;
     unsigned attrIndex = getNumAttributes();
     for (int i = 0; i < obj.arrayGetLength(); i++) {
-      if (obj.arrayGet(i, &iobj)->isDict()) {
+      Object iobj = obj.arrayGet(i);
+      if (iobj.isDict()) {
         attrIndex = getNumAttributes();
         parseAttributes(iobj.getDict());
       } else if (iobj.isInt()) {
@@ -1187,25 +1144,23 @@
       } else {
         error(errSyntaxWarning, -1, "A item is wrong type ({0:s})", iobj.getTypeName());
       }
-      iobj.free();
     }
   } else if (!obj.isNull()) {
     error(errSyntaxWarning, -1, "A is wrong type ({0:s})", obj.getTypeName());
   }
-  obj.free();
 
   // Attributes referenced indirectly through the ClassMap (optional).
   if (treeRoot->getClassMap()) {
-    Object classes;
-    if (element->lookup("C", &classes)->isName()) {
-      Object attr;
-      if (treeRoot->getClassMap()->lookup(classes.getName(), &attr)->isDict()) {
+    Object classes = element->lookup("C");
+    if (classes.isName()) {
+      Object attr = treeRoot->getClassMap()->lookup(classes.getName());
+      if (attr.isDict()) {
         parseAttributes(attr.getDict(), gTrue);
       } else if (attr.isArray()) {
         for (int i = 0; i < attr.arrayGetLength(); i++) {
-          Object iobj;
           unsigned attrIndex = getNumAttributes();
-          if (attr.arrayGet(i, &iobj)->isDict()) {
+          Object iobj = attr.arrayGet(i);
+          if (iobj.isDict()) {
             attrIndex = getNumAttributes();
             parseAttributes(iobj.getDict(), gTrue);
           } else if (iobj.isInt()) {
@@ -1216,13 +1171,10 @@
           } else {
             error(errSyntaxWarning, -1, "C item is wrong type ({0:s})", iobj.getTypeName());
           }
-          iobj.free();
         }
       } else if (!attr.isNull()) {
         error(errSyntaxWarning, -1, "C object is wrong type ({0:s})", classes.getTypeName());
       }
-      classes.free();
-      attr.free();
     }
   }
 }
@@ -1243,40 +1195,31 @@
      * TODO: The optional Stm/StwOwn attributes are not handled, so all the
      *      page will be always scanned when calling StructElement::getText().
      */
-    Object mcidObj;
-    Object pageRefObj;
-
-    if (!childObj->dictLookup("MCID", &mcidObj)->isInt()) {
+    Object mcidObj = childObj->dictLookup("MCID");
+    if (mcidObj.isInt()) {
       error(errSyntaxError, -1, "MCID object is wrong type ({0:s})", mcidObj.getTypeName());
-      mcidObj.free();
       return NULL;
     }
 
     child = new StructElement(mcidObj.getInt(), treeRoot, this);
-    mcidObj.free();
 
-    if (childObj->dictLookupNF("Pg", &pageRefObj)->isRef()) {
-      child->pageRef = pageRefObj;
-    } else {
-      pageRefObj.free();
+    Object pageRefObj = childObj->dictLookupNF("Pg");
+    if (pageRefObj.isRef()) {
+      child->pageRef = std::move(pageRefObj);
     }
   } else if (childObj->isDict("OBJR")) {
-    Object refObj;
-
-    if (childObj->dictLookupNF("Obj", &refObj)->isRef()) {
-      Object pageRefObj;
+    Object refObj = childObj->dictLookupNF("Obj");
+    if (refObj.isRef()) {
 
       child = new StructElement(refObj.getRef(), treeRoot, this);
 
-      if (childObj->dictLookupNF("Pg", &pageRefObj)->isRef()) {
-        child->pageRef = pageRefObj;
-      } else {
-        pageRefObj.free();
+      Object pageRefObj = childObj->dictLookupNF("Pg");
+      if (pageRefObj.isRef()) {
+        child->pageRef = std::move(pageRefObj);
       }
     } else {
       error(errSyntaxError, -1, "Obj object is wrong type ({0:s})", refObj.getTypeName());
     }
-    refObj.free();
   } else if (childObj->isDict()) {
     if (!ref->isRef()) {
       error(errSyntaxError, -1,
@@ -1310,34 +1253,29 @@
 
 void StructElement::parseChildren(Dict *element, std::set<int> &seen)
 {
-  Object kids;
-
-  if (element->lookup("K", &kids)->isArray()) {
+  Object kids = element->lookup("K");
+  if (kids.isArray()) {
     for (int i = 0; i < kids.arrayGetLength(); i++) {
-      Object obj, ref;
-      parseChild(kids.arrayGetNF(i, &ref), kids.arrayGet(i, &obj), seen);
-      obj.free();
-      ref.free();
+      Object obj = kids.arrayGet(i);
+      Object ref = kids.arrayGetNF(i);
+      parseChild(&ref, &obj, seen);
     }
   } else if (kids.isDict() || kids.isInt()) {
-    Object ref;
-    parseChild(element->lookupNF("K", &ref), &kids, seen);
-    ref.free();
+    Object ref = element->lookupNF("K");
+    parseChild(&ref, &kids, seen);
   }
-
-  kids.free();
 }
 
 void StructElement::parseAttributes(Dict *attributes, GBool keepExisting)
 {
-  Object owner;
-  if (attributes->lookup("O", &owner)->isName("UserProperties")) {
+  Object owner = attributes->lookup("O");
+  if (owner.isName("UserProperties")) {
     // In this case /P is an array of UserProperty dictionaries
-    Object userProperties;
-    if (attributes->lookup("P", &userProperties)->isArray()) {
+    Object userProperties = attributes->lookup("P");
+    if (userProperties.isArray()) {
       for (int i = 0; i < userProperties.arrayGetLength(); i++) {
-        Object property;
-        if (userProperties.arrayGet(i, &property)->isDict()) {
+        Object property = userProperties.arrayGet(i);
+        if (property.isDict()) {
           Attribute *attribute = Attribute::parseUserProperty(property.getDict());
           if (attribute && attribute->isOk()) {
             appendAttribute(attribute);
@@ -1348,10 +1286,8 @@
         } else {
           error(errSyntaxWarning, -1, "Item in P is wrong type ({0:s})", property.getTypeName());
         }
-        property.free();
       }
     }
-    userProperties.free();
   } else if (owner.isName()) {
     // In this case /P contains standard attributes.
     // Check first if the owner is a valid standard one.
@@ -1378,10 +1314,9 @@
           }
 
           if (type != Attribute::Unknown) {
-            Object value;
+            Object value = attributes->getVal(i);
             GBool typeCheckOk = gTrue;
-            Attribute *attribute = new Attribute(type, attributes->getVal(i, &value));
-            value.free();
+            Attribute *attribute = new Attribute(type, &value);
 
             if (attribute->isOk() && (typeCheckOk = attribute->checkType(this))) {
               appendAttribute(attribute);
@@ -1405,5 +1340,4 @@
   } else if (!owner.isNull()) {
     error(errSyntaxWarning, -1, "O is wrong type ({0:s})", owner.getTypeName());
   }
-  owner.free();
 }
diff --git a/poppler/StructTreeRoot.cc b/poppler/StructTreeRoot.cc
index b557e3a..b8c52c6 100644
--- a/poppler/StructTreeRoot.cc
+++ b/poppler/StructTreeRoot.cc
@@ -7,6 +7,7 @@
 // Copyright 2013, 2014 Igalia S.L.
 // Copyright 2014 Fabio D'Urso <fabiodurso@hotmail.it>
 // Copyright 2017 Jan-Erik S <janerik234678@gmail.com>
+// Copyright 2017 Albert Astals Cid <aacid@kde.org>
 //
 //========================================================================
 
@@ -36,8 +37,6 @@
 {
   for (ElemPtrArray::iterator i = elements.begin(); i != elements.end(); ++i)
     delete *i;
-  classMap.free();
-  roleMap.free();
 }
 
 void StructTreeRoot::parse(Dict *root)
@@ -45,55 +44,53 @@
   // The RoleMap/ClassMap dictionaries are needed by all the parsing
   // functions, which will resolve the custom names to canonical
   // standard names.
-  root->lookup("RoleMap", &roleMap);
-  root->lookup("ClassMap", &classMap);
+  roleMap = root->lookup("RoleMap");
+  classMap = root->lookup("ClassMap");
 
   // ParentTree (optional). If present, it must be a number tree,
   // otherwise it is not possible to map stream objects to their
   // corresponsing structure element. Here only the references are
   // loaded into the array, the pointers to the StructElements will
   // be filled-in later when parsing them.
-  Object obj;
-  if (root->lookup("ParentTree", &obj)->isDict()) {
-    Object nums;
-    if (obj.dictLookup("Nums", &nums)->isArray()) {
+  Object obj = root->lookup("ParentTree");
+  if (obj.isDict()) {
+    Object nums = obj.dictLookup("Nums");
+    if (nums.isArray()) {
       if (nums.arrayGetLength() % 2 == 0) {
         parentTree.resize(nums.arrayGetLength() / 2);
         // Index numbers in even positions, references in odd ones
         for (int i = 0; i < nums.arrayGetLength(); i += 2) {
-          Object index, value;
+          Object index = nums.arrayGet(i);
 
-          if (!nums.arrayGet(i, &index)->isInt()) {
+          if (!index.isInt()) {
             error(errSyntaxError, -1, "Nums item at position {0:d} is wrong type ({1:s})", i, index.getTypeName());
-            index.free();
             continue;
           }
           const unsigned idx = index.getInt();
           if (idx < 0 || idx >= parentTree.size()) {
             error(errSyntaxError, -1, "Nums item at position {0:d} is invalid value ({1:d}): [0..{2:d}]", i, idx, parentTree.size() - 1);
-            index.free();
             continue;
           }
 
-          if (nums.arrayGetNF(i + 1, &value)->isRef()) {
+          Object value = nums.arrayGetNF(i + 1);
+          if (value.isRef()) {
             parentTree[idx].resize(1);
             parentTree[idx][0].ref = value.getRef();
-          } else if (nums.arrayGet(i + 1, &value)->isArray()) {
-            parentTree[idx].resize(value.arrayGetLength());
-            for (int j = 0; j < value.arrayGetLength(); j++) {
-              Object itemvalue;
-              if (value.arrayGetNF(j, &itemvalue)->isRef())
-                parentTree[idx][j].ref = itemvalue.getRef();
-              else
-                error(errSyntaxError, -1, "Nums array item at position {0:d}/{1:d} is invalid type ({2:s})", i, j, itemvalue.getTypeName());
-              itemvalue.free();
-            }
           } else {
-            error(errSyntaxError, -1, "Nums item at position {0:d} is wrong type ({1:s})", i + 1, value.getTypeName());
-          }
-
-          value.free();
-          index.free();
+	    value = nums.arrayGet(i + 1);
+	    if (value.isArray()) {
+	      parentTree[idx].resize(value.arrayGetLength());
+	      for (int j = 0; j < value.arrayGetLength(); j++) {
+		Object itemvalue = value.arrayGetNF(j);
+		if (itemvalue.isRef())
+		  parentTree[idx][j].ref = itemvalue.getRef();
+		else
+		  error(errSyntaxError, -1, "Nums array item at position {0:d}/{1:d} is invalid type ({2:s})", i, j, itemvalue.getTypeName());
+	      }
+	    } else {
+	      error(errSyntaxError, -1, "Nums item at position {0:d} is wrong type ({1:s})", i + 1, value.getTypeName());
+	    }
+	  }
         }
       } else {
         error(errSyntaxError, -1, "Nums array length is not a even ({0:d})", nums.arrayGetLength());
@@ -101,26 +98,24 @@
     } else {
       error(errSyntaxError, -1, "Nums object is wrong type ({0:s})", nums.getTypeName());
     }
-    nums.free();
   }
-  obj.free();
 
   std::set<int> seenElements;
 
   // Parse the children StructElements
   const GBool marked = doc->getCatalog()->getMarkInfo() & Catalog::markInfoMarked;
-  Object kids;
-  if (root->lookup("K", &kids)->isArray()) {
+  Object kids = root->lookup("K");
+  if (kids.isArray()) {
     if (marked && kids.arrayGetLength() > 1) {
       error(errSyntaxWarning, -1, "K in StructTreeRoot has more than one children in a tagged PDF");
     }
     for (int i = 0; i < kids.arrayGetLength(); i++) {
-      Object obj, ref;
-      kids.arrayGetNF(i, &ref);
+      Object ref = kids.arrayGetNF(i);
       if (ref.isRef()) {
         seenElements.insert(ref.getRefNum());
       }
-      if (kids.arrayGet(i, &obj)->isDict()) {
+      Object obj = kids.arrayGet(i);
+      if (obj.isDict()) {
         StructElement *child = new StructElement(obj.getDict(), this, NULL, seenElements);
         if (child->isOk()) {
           if (marked && !(child->getType() == StructElement::Document ||
@@ -140,8 +135,6 @@
       } else {
         error(errSyntaxWarning, -1, "K has a child of wrong type ({0:s})", obj.getTypeName());
       }
-      obj.free();
-      ref.free();
     }
   } else if (kids.isDict()) {
     if (marked) {
@@ -150,10 +143,9 @@
     StructElement *child = new StructElement(kids.getDict(), this, NULL, seenElements);
     if (child->isOk()) {
       appendChild(child);
-      Object ref;
-      if (root->lookupNF("K", &ref)->isRef())
+      Object ref = root->lookupNF("K");
+      if (ref.isRef())
         parentTreeAdd(ref.getRef(), child);
-      ref.free();
     } else {
       error(errSyntaxWarning, -1, "StructTreeRoot element could not be parsed");
       delete child;
@@ -161,8 +153,6 @@
   } else if (!kids.isNull()) {
     error(errSyntaxWarning, -1, "K in StructTreeRoot is wrong type ({0:s})", kids.getTypeName());
   }
-
-  kids.free();
 }
 
 void StructTreeRoot::parentTreeAdd(const Ref &objectRef, StructElement *element)
diff --git a/poppler/TextOutputDev.cc b/poppler/TextOutputDev.cc
index d9993e9..a89ba23 100644
--- a/poppler/TextOutputDev.cc
+++ b/poppler/TextOutputDev.cc
@@ -20,7 +20,7 @@
 // Copyright (C) 2006 Jeff Muizelaar <jeff@infidigm.net>
 // Copyright (C) 2007, 2008, 2012 Adrian Johnson <ajohnson@redneon.com>
 // Copyright (C) 2008 Koji Otani <sho@bbr.jp>
-// Copyright (C) 2008, 2010-2012, 2014-2016 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2008, 2010-2012, 2014-2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2008 Pino Toscano <pino@kde.org>
 // Copyright (C) 2008, 2010 Hib Eris <hib@hiberis.nl>
 // Copyright (C) 2009 Ross Moore <ross@maths.mq.edu.au>
@@ -891,6 +891,7 @@
   // expand the array if needed
   if (unlikely((word->base / textPoolStep) > INT_MAX)) {
       error(errSyntaxWarning, -1, "word->base / textPoolStep > INT_MAX");
+      delete word;
       return;
   }
   wordBaseIdx = (int)(word->base / textPoolStep);
diff --git a/poppler/ViewerPreferences.cc b/poppler/ViewerPreferences.cc
index cba8d0a..e45134f 100644
--- a/poppler/ViewerPreferences.cc
+++ b/poppler/ViewerPreferences.cc
@@ -5,6 +5,7 @@
 // This file is licensed under the GPLv2 or later
 //
 // Copyright 2011 Pino Toscano <pino@kde.org>
+// Copyright 2017 Albert Astals Cid <aacid@kde.org>
 //
 //========================================================================
 
@@ -19,39 +20,38 @@
 {
   init();
 
-  Object obj;
-
-  if (prefDict->lookup("HideToolbar", &obj)->isBool()) {
+  Object obj = prefDict->lookup("HideToolbar");
+  if (obj.isBool()) {
     hideToolbar = obj.getBool();
   }
-  obj.free();
 
-  if (prefDict->lookup("HideMenubar", &obj)->isBool()) {
+  obj = prefDict->lookup("HideMenubar");
+  if (obj.isBool()) {
     hideMenubar = obj.getBool();
   }
-  obj.free();
 
-  if (prefDict->lookup("HideWindowUI", &obj)->isBool()) {
+  obj = prefDict->lookup("HideWindowUI");
+  if (obj.isBool()) {
     hideWindowUI = obj.getBool();
   }
-  obj.free();
 
-  if (prefDict->lookup("FitWindow", &obj)->isBool()) {
+  obj = prefDict->lookup("FitWindow");
+  if (obj.isBool()) {
     fitWindow = obj.getBool();
   }
-  obj.free();
 
-  if (prefDict->lookup("CenterWindow", &obj)->isBool()) {
+  obj = prefDict->lookup("CenterWindow");
+  if (obj.isBool()) {
     centerWindow = obj.getBool();
   }
-  obj.free();
 
-  if (prefDict->lookup("DisplayDocTitle", &obj)->isBool()) {
+  obj = prefDict->lookup("DisplayDocTitle");
+  if (obj.isBool()) {
     displayDocTitle = obj.getBool();
   }
-  obj.free();
 
-  if (prefDict->lookup("NonFullScreenPageMode", &obj)->isName()) {
+  obj = prefDict->lookup("NonFullScreenPageMode");
+  if (obj.isName()) {
     const char *mode = obj.getName();
     if (!strcmp(mode, "UseNone")) {
       nonFullScreenPageMode = nfpmUseNone;
@@ -63,9 +63,9 @@
       nonFullScreenPageMode = nfpmUseOC;
     }
   }
-  obj.free();
 
-  if (prefDict->lookup("Direction", &obj)->isName()) {
+  obj = prefDict->lookup("Direction");
+  if (obj.isName()) {
     const char *dir = obj.getName();
     if (!strcmp(dir, "L2R")) {
       direction = directionL2R;
@@ -73,9 +73,9 @@
       direction = directionR2L;
     }
   }
-  obj.free();
 
-  if (prefDict->lookup("PrintScaling", &obj)->isName()) {
+  obj = prefDict->lookup("PrintScaling");
+  if (obj.isName()) {
     const char *ps = obj.getName();
     if (!strcmp(ps, "None")) {
       printScaling = printScalingNone;
@@ -83,9 +83,9 @@
       printScaling = printScalingAppDefault;
     }
   }
-  obj.free();
 
-  if (prefDict->lookup("Duplex", &obj)->isName()) {
+  obj = prefDict->lookup("Duplex");
+  if (obj.isName()) {
     const char *d = obj.getName();
     if (!strcmp(d, "Simplex")) {
       duplex = duplexSimplex;
@@ -95,7 +95,6 @@
       duplex = duplexDuplexFlipLongEdge;
     }
   }
-  obj.free();
 }
 
 ViewerPreferences::~ViewerPreferences()
diff --git a/poppler/XRef.cc b/poppler/XRef.cc
index 6ea0fbb..1052601 100644
--- a/poppler/XRef.cc
+++ b/poppler/XRef.cc
@@ -99,7 +99,7 @@
 
   // Get the <objIdx>th object from this stream, which should be
   // object number <objNum>, generation 0.
-  Object *getObject(int objIdx, int objNum, Object *obj);
+  Object getObject(int objIdx, int objNum);
 
 private:
 
@@ -145,7 +145,7 @@
   Stream *str;
   Parser *parser;
   Goffset *offsets;
-  Object objStr, obj1, obj2;
+  Object objStr, obj1;
   Goffset first;
   int i;
 
@@ -155,32 +155,30 @@
   objNums = NULL;
   ok = gFalse;
 
-  if (!xref->fetch(objStrNum, 0, &objStr, recursion)->isStream()) {
-    goto err1;
+  objStr = xref->fetch(objStrNum, 0, recursion);
+  if (!objStr.isStream()) {
+    return;
   }
 
-  if (!objStr.streamGetDict()->lookup("N", &obj1, recursion)->isInt()) {
-    obj1.free();
-    goto err1;
+  obj1 = objStr.streamGetDict()->lookup("N", recursion);
+  if (!obj1.isInt()) {
+    return;
   }
   nObjects = obj1.getInt();
-  obj1.free();
   if (nObjects <= 0) {
-    goto err1;
+    return;
   }
 
-  objStr.streamGetDict()->lookup("First", &obj1, recursion);
+  obj1 = objStr.streamGetDict()->lookup("First", recursion);
   if (!obj1.isInt() && !obj1.isInt64()) {
-    obj1.free();
-    goto err1;
+    return;
   }
   if (obj1.isInt())
     first = obj1.getInt();
   else
     first = obj1.getInt64();
-  obj1.free();
   if (first < 0) {
-    goto err1;
+    return;
   }
 
   // this is an arbitrary limit to avoid integer overflow problems
@@ -188,7 +186,7 @@
   // object streams to 100-200 objects)
   if (nObjects > 1000000) {
     error(errSyntaxError, -1, "Too many objects in an object stream");
-    goto err1;
+    return;
   }
   objs = new Object[nObjects];
   objNums = (int *)gmallocn(nObjects, sizeof(int));
@@ -196,31 +194,26 @@
 
   // parse the header: object numbers and offsets
   objStr.streamReset();
-  obj1.initNull();
-  str = new EmbedStream(objStr.getStream(), &obj1, gTrue, first);
+  str = new EmbedStream(objStr.getStream(), Object(objNull), gTrue, first);
   parser = new Parser(xref, new Lexer(xref, str), gFalse);
   for (i = 0; i < nObjects; ++i) {
-    parser->getObj(&obj1);
-    parser->getObj(&obj2);
+    obj1 = parser->getObj();
+    Object obj2 = parser->getObj();
     if (!obj1.isInt() || !(obj2.isInt() || obj2.isInt64())) {
-      obj1.free();
-      obj2.free();
       delete parser;
       gfree(offsets);
-      goto err1;
+      return;
     }
     objNums[i] = obj1.getInt();
     if (obj2.isInt())
       offsets[i] = obj2.getInt();
     else
       offsets[i] = obj2.getInt64();
-    obj1.free();
-    obj2.free();
     if (objNums[i] < 0 || offsets[i] < 0 ||
 	(i > 0 && offsets[i] < offsets[i-1])) {
       delete parser;
       gfree(offsets);
-      goto err1;
+      return;
     }
   }
   while (str->getChar() != EOF) ;
@@ -235,43 +228,32 @@
 
   // parse the objects
   for (i = 0; i < nObjects; ++i) {
-    obj1.initNull();
     if (i == nObjects - 1) {
-      str = new EmbedStream(objStr.getStream(), &obj1, gFalse, 0);
+      str = new EmbedStream(objStr.getStream(), Object(objNull), gFalse, 0);
     } else {
-      str = new EmbedStream(objStr.getStream(), &obj1, gTrue,
+      str = new EmbedStream(objStr.getStream(), Object(objNull), gTrue,
 			    offsets[i+1] - offsets[i]);
     }
     parser = new Parser(xref, new Lexer(xref, str), gFalse);
-    parser->getObj(&objs[i]);
+    objs[i] = parser->getObj();
     while (str->getChar() != EOF) ;
     delete parser;
   }
 
   gfree(offsets);
   ok = gTrue;
-
- err1:
-  objStr.free();
 }
 
 ObjectStream::~ObjectStream() {
-  int i;
-
-  if (objs) {
-    for (i = 0; i < nObjects; ++i) {
-      objs[i].free();
-    }
-    delete[] objs;
-  }
+  delete[] objs;
   gfree(objNums);
 }
 
-Object *ObjectStream::getObject(int objIdx, int objNum, Object *obj) {
+Object ObjectStream::getObject(int objIdx, int objNum) {
   if (objIdx < 0 || objIdx >= nObjects || objNum != objNums[objIdx]) {
-    return obj->initNull();
+    return Object(objNull);
   }
-  return objs[objIdx].copy(obj);
+  return objs[objIdx].copy();
 }
 
 //------------------------------------------------------------------------
@@ -311,7 +293,7 @@
   init();
 
   if (trailerDictA->isDict())
-    trailerDict.initDict(trailerDictA->getDict());
+    trailerDict = trailerDictA->copy();
 }
 
 XRef::XRef(BaseStream *strA, Goffset pos, Goffset mainXRefEntriesOffsetA, GBool *wasReconstructed, GBool reconstruct) {
@@ -356,30 +338,26 @@
     }
 
     // set size to (at least) the size specified in trailer dict
-    trailerDict.dictLookupNF("Size", &obj);
+    obj = trailerDict.dictLookupNF("Size");
     if (!obj.isInt()) {
         error(errSyntaxWarning, -1, "No valid XRef size in trailer");
     } else {
       if (obj.getInt() > size) {
          if (resize(obj.getInt()) != obj.getInt()) {
             if (!(ok = constructXRef(wasReconstructed))) {
-               obj.free();
                errCode = errDamaged;
                return;
             }
          }
       }
     }
-    obj.free();
 
     // get the root dictionary (catalog) object
-    trailerDict.dictLookupNF("Root", &obj);
+    obj = trailerDict.dictLookupNF("Root");
     if (obj.isRef()) {
       rootNum = obj.getRefNum();
       rootGen = obj.getRefGen();
-      obj.free();
     } else {
-      obj.free();
       if (!(ok = constructXRef(wasReconstructed))) {
         errCode = errDamaged;
         return;
@@ -397,7 +375,6 @@
   }
   gfree(entries);
 
-  trailerDict.free();
   if (streamEnds) {
     gfree(streamEnds);
   }
@@ -426,7 +403,7 @@
   xref->prevXRefOffset = prevXRefOffset;
   xref->mainXRefEntriesOffset = mainXRefEntriesOffset;
   xref->xRefStream = xRefStream;
-  trailerDict.copy(&xref->trailerDict);
+  xref->trailerDict = trailerDict.copy();
   xref->encAlgorithm = encAlgorithm;
   xref->encRevision = encRevision;
   xref->encVersion = encVersion;
@@ -446,7 +423,7 @@
   for (int i = 0; i < size; ++i) {
     xref->entries[i].offset = entries[i].offset;
     xref->entries[i].type = entries[i].type;
-    xref->entries[i].obj.initNull ();
+    xref->entries[i].obj.setToNull();
     xref->entries[i].flags = entries[i].flags;
     xref->entries[i].gen = entries[i].gen;
   }
@@ -495,7 +472,7 @@
     for (int i = size; i < newSize; ++i) {
       entries[i].offset = -1;
       entries[i].type = xrefEntryNone;
-      entries[i].obj.initNull ();
+      entries[i].obj.initNullAfterMalloc ();
       entries[i].flags = 0;
       entries[i].gen = 0;
     }
@@ -529,31 +506,26 @@
   GBool more;
 
   // start up a parser, parse one token
-  obj.initNull();
   parser = new Parser(NULL,
 	     new Lexer(NULL,
-	       str->makeSubStream(start + *pos, gFalse, 0, &obj)),
+	       str->makeSubStream(start + *pos, gFalse, 0, Object(objNull))),
 	     gTrue);
-  parser->getObj(&obj, gTrue);
+  obj = parser->getObj(gTrue);
 
   // parse an old-style xref table
   if (obj.isCmd("xref")) {
-    obj.free();
     more = readXRefTable(parser, pos, followedXRefStm, xrefStreamObjsNum);
 
   // parse an xref stream
   } else if (obj.isInt()) {
     const int objNum = obj.getInt();
-    obj.free();
-    if (!parser->getObj(&obj, gTrue)->isInt()) {
+    if (obj = parser->getObj(gTrue), !obj.isInt()) {
       goto err1;
     }
-    obj.free();
-    if (!parser->getObj(&obj, gTrue)->isCmd("obj")) {
+    if (obj = parser->getObj(gTrue), !obj.isCmd("obj")) {
       goto err1;
     }
-    obj.free();
-    if (!parser->getObj(&obj)->isStream()) {
+    if (obj = parser->getObj(), !obj.isStream()) {
       goto err1;
     }
     if (trailerDict.isNone()) {
@@ -563,7 +535,6 @@
       xrefStreamObjsNum->push_back(objNum);
     }
     more = readXRefStream(obj.getStream(), pos);
-    obj.free();
 
   } else {
     goto err1;
@@ -573,7 +544,6 @@
   return more;
 
  err1:
-  obj.free();
   delete parser;
   ok = gFalse;
   return gFalse;
@@ -587,21 +557,19 @@
   int first, n, i;
 
   while (1) {
-    parser->getObj(&obj, gTrue);
+    obj = parser->getObj(gTrue);
     if (obj.isCmd("trailer")) {
-      obj.free();
       break;
     }
     if (!obj.isInt()) {
-      goto err1;
+      goto err0;
     }
     first = obj.getInt();
-    obj.free();
-    if (!parser->getObj(&obj, gTrue)->isInt()) {
-      goto err1;
+    obj = parser->getObj(gTrue);
+    if (!obj.isInt()) {
+      goto err0;
     }
     n = obj.getInt();
-    obj.free();
     if (first < 0 || n < 0 || first + n < 0) {
       goto err0;
     }
@@ -612,33 +580,35 @@
       }
     }
     for (i = first; i < first + n; ++i) {
-      parser->getObj(&obj, gTrue);
+      obj = parser->getObj(gTrue);
       if (obj.isInt()) {
 	entry.offset = obj.getInt();
       } else if (obj.isInt64()) {
 	entry.offset = obj.getInt64();
       } else {
-	goto err1;
+	goto err0;
       }
-      obj.free();
-      if (!parser->getObj(&obj, gTrue)->isInt()) {
-	goto err1;
+      obj = parser->getObj(gTrue);
+      if (!obj.isInt()) {
+	goto err0;
       }
       entry.gen = obj.getInt();
-      entry.obj.initNull ();
       entry.flags = 0;
-      obj.free();
-      parser->getObj(&obj, gTrue);
+      obj = parser->getObj(gTrue);
       if (obj.isCmd("n")) {
 	entry.type = xrefEntryUncompressed;
       } else if (obj.isCmd("f")) {
 	entry.type = xrefEntryFree;
       } else {
-	goto err1;
+	goto err0;
       }
-      obj.free();
       if (entries[i].offset == -1) {
-	entries[i] = entry;
+	entries[i].offset = entry.offset;
+	entries[i].gen = entry.gen;
+	entries[i].type = entry.type;
+	entries[i].flags = entry.flags;
+	entries[i].obj.setToNull();
+
 	// PDF files of patents from the IBM Intellectual Property
 	// Network have a bug: the xref table claims to start at 1
 	// instead of 0.
@@ -646,7 +616,12 @@
 	    entries[1].offset == 0 && entries[1].gen == 65535 &&
 	    entries[1].type == xrefEntryFree) {
 	  i = first = 0;
-	  entries[0] = entries[1];
+	  entries[0].offset = 0;
+	  entries[0].gen = 65535;
+	  entries[0].type = xrefEntryFree;
+	  entries[0].flags = entries[1].flags;
+	  entries[0].obj = std::move(entries[1].obj);
+
 	  entries[1].offset = -1;
 	}
       }
@@ -654,12 +629,13 @@
   }
 
   // read the trailer dictionary
-  if (!parser->getObj(&obj)->isDict()) {
-    goto err1;
+  obj = parser->getObj();
+  if (!obj.isDict()) {
+    goto err0;
   }
 
   // get the 'Prev' pointer
-  obj.getDict()->lookupNF("Prev", &obj2);
+  obj2 = obj.getDict()->lookupNF("Prev");
   if (obj2.isInt() || obj2.isInt64()) {
     if (obj2.isInt())
       pos2 = obj2.getInt();
@@ -686,15 +662,14 @@
   } else {
     more = gFalse;
   }
-  obj2.free();
 
   // save the first trailer dictionary
   if (trailerDict.isNone()) {
-    obj.copy(&trailerDict);
+    trailerDict = obj.copy();
   }
 
   // check for an 'XRefStm' key
-  obj.getDict()->lookup("XRefStm", &obj2);
+  obj2 = obj.getDict()->lookup("XRefStm");
   if (obj2.isInt() || obj2.isInt64()) {
     if (obj2.isInt())
       pos2 = obj2.getInt();
@@ -710,97 +685,84 @@
       readXRef(&pos2, followedXRefStm, xrefStreamObjsNum);
     }
     if (!ok) {
-      obj2.free();
-      goto err1;
+      goto err0;
     }
   }
-  obj2.free();
 
-  obj.free();
   return more;
 
- err1:
-  obj.free();
  err0:
   ok = gFalse;
   return gFalse;
 }
 
 GBool XRef::readXRefStream(Stream *xrefStr, Goffset *pos) {
-  Dict *dict;
   int w[3];
   GBool more;
-  Object obj, obj2, idx;
-  int newSize, first, n, i;
+  Object obj;
 
-  dict = xrefStr->getDict();
+  ok = gFalse;
 
-  if (!dict->lookupNF("Size", &obj)->isInt()) {
-    goto err1;
+  Dict *dict = xrefStr->getDict();
+  obj = dict->lookupNF("Size");
+  if (!obj.isInt()) {
+    return gFalse;
   }
-  newSize = obj.getInt();
-  obj.free();
+  int newSize = obj.getInt();
   if (newSize < 0) {
-    goto err1;
+    return gFalse;
   }
   if (newSize > size) {
     if (resize(newSize) != newSize) {
       error(errSyntaxError, -1, "Invalid 'size' parameter");
-      goto err0;
+      return gFalse;
     }
   }
 
-  if (!dict->lookupNF("W", &obj)->isArray() ||
-      obj.arrayGetLength() < 3) {
-    goto err1;
+  obj = dict->lookupNF("W");
+  if (!obj.isArray() || obj.arrayGetLength() < 3) {
+    return gFalse;
   }
-  for (i = 0; i < 3; ++i) {
-    if (!obj.arrayGet(i, &obj2)->isInt()) {
-      obj2.free();
-      goto err1;
+  for (int i = 0; i < 3; ++i) {
+    Object obj2 = obj.arrayGet(i);
+    if (!obj2.isInt()) {
+      return gFalse;
     }
     w[i] = obj2.getInt();
-    obj2.free();
     if (w[i] < 0) {
-      goto err1;
+      return gFalse;
     }
   }
-  obj.free();
   if (w[0] > (int)sizeof(int) || w[1] > (int)sizeof(long long) || w[2] > (int)sizeof(int)) {
-    goto err1;
+    return gFalse;
   }
 
   xrefStr->reset();
-  dict->lookupNF("Index", &idx);
+  Object idx = dict->lookupNF("Index");
   if (idx.isArray()) {
-    for (i = 0; i+1 < idx.arrayGetLength(); i += 2) {
-      if (!idx.arrayGet(i, &obj)->isInt()) {
-	idx.free();
-	goto err1;
+    for (int i = 0; i+1 < idx.arrayGetLength(); i += 2) {
+      obj = idx.arrayGet(i);
+      if (!obj.isInt()) {
+	return gFalse;
       }
-      first = obj.getInt();
-      obj.free();
-      if (!idx.arrayGet(i+1, &obj)->isInt()) {
-	idx.free();
-	goto err1;
+      int first = obj.getInt();
+      obj = idx.arrayGet(i+1);
+      if (!obj.isInt()) {
+	return gFalse;
       }
-      n = obj.getInt();
-      obj.free();
+      int n = obj.getInt();
       if (first < 0 || n < 0 ||
 	  !readXRefStreamSection(xrefStr, w, first, n)) {
-	idx.free();
-	goto err0;
+	return gFalse;
       }
     }
   } else {
     if (!readXRefStreamSection(xrefStr, w, 0, newSize)) {
-      idx.free();
-      goto err0;
+      return gFalse;
     }
   }
-  idx.free();
 
-  dict->lookupNF("Prev", &obj);
+  obj = dict->lookupNF("Prev");
   if (obj.isInt()) {
     *pos = obj.getInt();
     more = gTrue;
@@ -810,18 +772,12 @@
   } else {
     more = gFalse;
   }
-  obj.free();
   if (trailerDict.isNone()) {
-    trailerDict.initDict(dict);
+    trailerDict = xrefStr->getDictObject()->copy();
   }
 
+  ok = gTrue;
   return more;
-
- err1:
-  obj.free();
- err0:
-  ok = gFalse;
-  return gFalse;
 }
 
 GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) {
@@ -897,7 +853,7 @@
 // Attempt to construct an xref table for a damaged file.
 GBool XRef::constructXRef(GBool *wasReconstructed, GBool needCatalogDict) {
   Parser *parser;
-  Object newTrailerDict, obj;
+  Object obj;
   char buf[256];
   Goffset pos;
   int num, gen;
@@ -909,6 +865,7 @@
   bool oneCycle = true;
   int offset = 0;
 
+  resize(0); // free entries properly
   gfree(entries);
   capacity = 0;
   size = 0;
@@ -947,26 +904,20 @@
 
       // got trailer dictionary
       if (!strncmp(p, "trailer", 7)) {
-        obj.initNull();
         parser = new Parser(NULL,
 		 new Lexer(NULL,
-		   str->makeSubStream(pos + 7, gFalse, 0, &obj)),
+		   str->makeSubStream(pos + 7, gFalse, 0, Object(objNull))),
 		 gFalse);
-        parser->getObj(&newTrailerDict);
+        Object newTrailerDict = parser->getObj();
         if (newTrailerDict.isDict()) {
-	  newTrailerDict.dictLookupNF("Root", &obj);
+	  obj = newTrailerDict.dictLookupNF("Root");
 	  if (obj.isRef() && (!gotRoot || !needCatalogDict) && rootNum != obj.getRefNum()) {
 	    rootNum = obj.getRefNum();
 	    rootGen = obj.getRefGen();
-	    if (!trailerDict.isNone()) {
-	      trailerDict.free();
-	    }
-	    newTrailerDict.copy(&trailerDict);
+	    trailerDict = newTrailerDict.copy();
 	    gotRoot = gTrue;
 	  }
-	  obj.free();
         }
-        newTrailerDict.free();
         delete parser;
 
       // look for object
@@ -1143,20 +1094,19 @@
   return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permAssemble);
 }
 
-Object *XRef::getCatalog(Object *catalog) {
-  fetch(rootNum, rootGen, catalog);
-  if (catalog->isDict()) {
+Object XRef::getCatalog() {
+  Object catalog = fetch(rootNum, rootGen);
+  if (catalog.isDict()) {
     return catalog;
   }
   GBool wasReconstructed = false;
   if (constructXRef(&wasReconstructed, gTrue)) {
-    catalog->free();
-    fetch(rootNum, rootGen, catalog);
+    catalog = fetch(rootNum, rootGen);
   }
   return catalog;
 }
 
-Object *XRef::fetch(int num, int gen, Object *obj, int recursion) {
+Object XRef::fetch(int num, int gen, int recursion) {
   XRefEntry *e;
   Parser *parser;
   Object obj1, obj2, obj3;
@@ -1169,24 +1119,23 @@
 
   e = getEntry(num);
   if(!e->obj.isNull ()) { //check for updated object
-    obj = e->obj.copy(obj);
-    return obj;
+    return e->obj.copy();
   }
 
   switch (e->type) {
 
   case xrefEntryUncompressed:
+  {
     if (e->gen != gen) {
       goto err;
     }
-    obj1.initNull();
     parser = new Parser(this,
 	       new Lexer(this,
-		 str->makeSubStream(start + e->offset, gFalse, 0, &obj1)),
+		 str->makeSubStream(start + e->offset, gFalse, 0, Object(objNull))),
 	       gTrue);
-    parser->getObj(&obj1, recursion);
-    parser->getObj(&obj2, recursion);
-    parser->getObj(&obj3, recursion);
+    obj1 = parser->getObj(recursion);
+    obj2 = parser->getObj(recursion);
+    obj3 = parser->getObj(recursion);
     if (!obj1.isInt() || obj1.getInt() != num ||
 	!obj2.isInt() || obj2.getInt() != gen ||
 	!obj3.isCmd("obj")) {
@@ -1205,28 +1154,19 @@
 	  if (longNumber <= INT_MAX && longNumber >= INT_MIN && *end_ptr == '\0') {
 	    int number = longNumber;
 	    error(errSyntaxWarning, -1, "Cmd was not obj but {0:s}, assuming the creator meant obj {1:d}", cmd, number);
-	    obj->initInt(number);
-	    obj1.free();
-	    obj2.free();
-	    obj3.free();
 	    delete parser;
-	    break;
+	    return Object(number);
 	  }
 	}
       }
-      obj1.free();
-      obj2.free();
-      obj3.free();
       delete parser;
       goto err;
     }
-    parser->getObj(obj, gFalse, (encrypted && !e->getFlag(XRefEntry::Unencrypted)) ? fileKey : NULL,
+    Object obj = parser->getObj(gFalse, (encrypted && !e->getFlag(XRefEntry::Unencrypted)) ? fileKey : NULL,
 		   encAlgorithm, keyLength, num, gen, recursion);
-    obj1.free();
-    obj2.free();
-    obj3.free();
     delete parser;
-    break;
+    return obj;
+  }
 
   case xrefEntryCompressed:
   {
@@ -1263,24 +1203,21 @@
 	objStrs->put(newkey, newitem);
       }
     }
-    objStr->getObject(e->gen, num, obj);
+    return objStr->getObject(e->gen, num);
   }
-  break;
 
   default:
     goto err;
   }
   
-  return obj;
-
  err:
   if (!xRefStream && !xrefReconstructed) {
     error(errInternal, -1, "xref num {0:d} not found but needed, try to reconstruct\n", num);
     rootNum = -1;
     constructXRef(&xrefReconstructed);
-    return fetch(num, gen, obj, ++recursion);
+    return fetch(num, gen, ++recursion);
   }
-  return obj->initNull();
+  return Object(objNull);
 }
 
 void XRef::lock() {
@@ -1295,43 +1232,34 @@
 #endif
 }
 
-Object *XRef::getDocInfo(Object *obj) {
-  return trailerDict.dictLookup("Info", obj);
+Object XRef::getDocInfo() {
+  return trailerDict.dictLookup("Info");
 }
 
 // Added for the pdftex project.
-Object *XRef::getDocInfoNF(Object *obj) {
-  return trailerDict.dictLookupNF("Info", obj);
+Object XRef::getDocInfoNF() {
+  return trailerDict.dictLookupNF("Info");
 }
 
-Object *XRef::createDocInfoIfNoneExists(Object *obj) {
-  getDocInfo(obj);
+Object XRef::createDocInfoIfNoneExists() {
+  Object obj = getDocInfo();
 
-  if (obj->isDict()) {
+  if (obj.isDict()) {
     return obj;
-  } else if (!obj->isNull()) {
+  } else if (!obj.isNull()) {
     // DocInfo exists, but isn't a dictionary (doesn't comply with the PDF reference)
-    obj->free();
     removeDocInfo();
   }
 
-  obj->initDict(this);
-
-  Ref ref = addIndirectObject(obj);
-
-  Object objRef;
-  objRef.initRef(ref.num, ref.gen);
-
-  trailerDict.dictSet("Info", &objRef);
-
-  objRef.free();
+  obj = Object(new Dict(this));
+  const Ref ref = addIndirectObject(&obj);
+  trailerDict.dictSet("Info", Object(ref.num, ref.gen));
 
   return obj;
 }
 
 void XRef::removeDocInfo() {
-  Object infoObjRef;
-  getDocInfoNF(&infoObjRef);
+  Object infoObjRef = getDocInfoNF();
   if (infoObjRef.isNull()) {
     return;
   }
@@ -1339,7 +1267,6 @@
   trailerDict.dictRemove("Info");
 
   removeIndirectObject(infoObjRef.getRef());
-  infoObjRef.free();
 }
 
 GBool XRef::getStreamEnd(Goffset streamStart, Goffset *streamEnd) {
@@ -1396,7 +1323,7 @@
     for (int i = size; i < num + 1; ++i) {
       entries[i].offset = -1;
       entries[i].type = xrefEntryFree;
-      entries[i].obj.initNull ();
+      entries[i].obj.initNullAfterMalloc();
       entries[i].flags = 0;
       entries[i].gen = 0;
     }
@@ -1404,7 +1331,7 @@
   }
   XRefEntry *e = getEntry(num);
   e->gen = gen;
-  e->obj.initNull ();
+  e->obj.setToNull();
   e->flags = 0;
   if (used) {
     e->type = xrefEntryUncompressed;
@@ -1422,8 +1349,7 @@
     return;
   }
   XRefEntry *e = getEntry(r.num);
-  e->obj.free();
-  o->copy(&(e->obj));
+  e->obj = o->copy();
   e->setFlag(XRefEntry::Updated, gTrue);
   setModified();
 }
@@ -1449,7 +1375,7 @@
     //incremented when the object was deleted
   }
   e->type = xrefEntryUncompressed;
-  o->copy(&e->obj);
+  e->obj = o->copy();
   e->setFlag(XRefEntry::Updated, gTrue);
   setModified();
 
@@ -1538,16 +1464,15 @@
   writeXRef(&writer, writeAllEntries);
 }
 
-XRef::XRefStreamWriter::XRefStreamWriter(Object *indexA, GooString *stmBufA, int offsetSizeA) {
+XRef::XRefStreamWriter::XRefStreamWriter(Array *indexA, GooString *stmBufA, int offsetSizeA) {
   index = indexA;
   stmBuf = stmBufA;
   offsetSize = offsetSizeA;
 }
 
 void XRef::XRefStreamWriter::startSection(int first, int count) {
-  Object obj;
-  index->arrayAdd( obj.initInt(first) );
-  index->arrayAdd( obj.initInt(count) );
+  index->add( Object(first) );
+  index->add( Object(count) );
 }
 
 void XRef::XRefStreamWriter::writeEntry(Goffset offset, int gen, XRefEntryType type) {
@@ -1576,8 +1501,7 @@
 }
 
 void XRef::writeStreamToBuffer(GooString *stmBuf, Dict *xrefDict, XRef *xref) {
-  Object index;
-  index.initArray(xref);
+  Array *index = new Array(xref);
   stmBuf->clear();
 
   // First pass: determine whether all offsets fit in 4 bytes or not
@@ -1586,47 +1510,41 @@
   const int offsetSize = prescan.hasOffsetsBeyond4GB ? sizeof(Goffset) : 4;
 
   // Second pass: actually write the xref stream
-  XRefStreamWriter writer(&index, stmBuf, offsetSize);
+  XRefStreamWriter writer(index, stmBuf, offsetSize);
   writeXRef(&writer, gFalse);
 
-  Object obj1, obj2;
-  xrefDict->set("Type", obj1.initName("XRef"));
-  xrefDict->set("Index", &index);
-  obj2.initArray(xref);
-  obj2.arrayAdd( obj1.initInt(1) );
-  obj2.arrayAdd( obj1.initInt(offsetSize) );
-  obj2.arrayAdd( obj1.initInt(2) );
-  xrefDict->set("W", &obj2);
+  xrefDict->set("Type", Object(objName, "XRef"));
+  xrefDict->set("Index", Object(index));
+  Array *wArray = new Array(xref);
+  wArray->add( Object(1) );
+  wArray->add( Object(offsetSize) );
+  wArray->add( Object(2) );
+  xrefDict->set("W", Object(wArray));
 }
 
 GBool XRef::parseEntry(Goffset offset, XRefEntry *entry)
 {
   GBool r;
 
-  Object obj;
-  obj.initNull();
-  Parser parser = Parser(NULL, new Lexer(NULL,
-     str->makeSubStream(offset, gFalse, 20, &obj)), gTrue);
+  Parser parser(NULL, new Lexer(NULL,
+     str->makeSubStream(offset, gFalse, 20, Object(objNull))), gTrue);
 
   Object obj1, obj2, obj3;
-  if (((parser.getObj(&obj1)->isInt()) || obj1.isInt64()) &&
-      (parser.getObj(&obj2)->isInt()) &&
-      (parser.getObj(&obj3)->isCmd("n") || obj3.isCmd("f"))) {
+  if (((obj1 = parser.getObj(), obj1.isInt()) || obj1.isInt64()) &&
+      (obj2 = parser.getObj(), obj2.isInt()) &&
+      (obj3 = parser.getObj(), obj3.isCmd("n") || obj3.isCmd("f"))) {
     if (obj1.isInt64())
       entry->offset = obj1.getInt64();
     else
       entry->offset = obj1.getInt();
     entry->gen = obj2.getInt();
     entry->type = obj3.isCmd("n") ? xrefEntryUncompressed : xrefEntryFree;
-    entry->obj.initNull ();
+    entry->obj.setToNull();
     entry->flags = 0;
     r = gTrue;
   } else {
     r = gFalse;
   }
-  obj1.free();
-  obj2.free();
-  obj3.free();
 
   return r;
 }
@@ -1719,8 +1637,8 @@
     {
       Array *array = obj->getArray();
       for (int i = 0; i < array->getLength(); i++) {
-        markUnencrypted(array->getNF(i, &obj1));
-        obj1.free();
+	obj1 = array->getNF(i);
+        markUnencrypted(&obj1);
       }
       break;
     }
@@ -1735,8 +1653,8 @@
         dict = obj->getDict();
       }
       for (int i = 0; i < dict->getLength(); i++) {
-        markUnencrypted(dict->getValNF(i, &obj1));
-        obj1.free();
+	obj1 = dict->getValNF(i);
+        markUnencrypted(&obj1);
       }
       break;
     }
@@ -1747,9 +1665,8 @@
       if (e->getFlag(XRefEntry::Unencrypted))
         return; // We've already been here: prevent infinite recursion
       e->setFlag(XRefEntry::Unencrypted, gTrue);
-      fetch(ref.num, ref.gen, &obj1);
+      obj1 = fetch(ref.num, ref.gen);
       markUnencrypted(&obj1);
-      obj1.free();
       break;
     }
     default:
@@ -1793,19 +1710,16 @@
   }
 
   // Mark objects referred from the Encrypt dict as Unencrypted
-  Object obj;
-  markUnencrypted(trailerDict.dictLookupNF("Encrypt", &obj));
-  obj.free();
+  Object obj = trailerDict.dictLookupNF("Encrypt");
+  markUnencrypted();
 }
 
 void XRef::markUnencrypted() {
   // Mark objects referred from the Encrypt dict as Unencrypted
-  Object obj;
-  trailerDict.dictLookupNF("Encrypt", &obj);
+  Object obj = trailerDict.dictLookupNF("Encrypt");
   if (obj.isRef()) {
     XRefEntry *e = getEntry(obj.getRefNum());
     e->setFlag(XRefEntry::Unencrypted, gTrue);
   }
-  obj.free();
 }
 
diff --git a/poppler/XRef.h b/poppler/XRef.h
index 0439161..e59e8cb 100644
--- a/poppler/XRef.h
+++ b/poppler/XRef.h
@@ -14,7 +14,7 @@
 // under GPL version 2 or later
 //
 // Copyright (C) 2005 Brad Hards <bradh@frogmouth.net>
-// Copyright (C) 2006, 2008, 2010-2013 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006, 2008, 2010-2013, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2007-2008 Julien Rebetez <julienr@svn.gnome.org>
 // Copyright (C) 2007 Carlos Garcia Campos <carlosgc@gnome.org>
 // Copyright (C) 2010 Ilya Gorenbein <igorenbein@finjan.com>
@@ -141,18 +141,18 @@
   int getPermFlags() { return permFlags; }
 
   // Get catalog object.
-  Object *getCatalog(Object *obj);
+  Object getCatalog();
 
   // Fetch an indirect reference.
-  Object *fetch(int num, int gen, Object *obj, int recursion = 0);
+  Object fetch(int num, int gen, int recursion = 0);
 
   // Return the document's Info dictionary (if any).
-  Object *getDocInfo(Object *obj);
-  Object *getDocInfoNF(Object *obj);
+  Object getDocInfo();
+  Object getDocInfoNF();
 
   // Create and return the document's Info dictionary if none exists.
   // Otherwise return the existing one.
-  Object *createDocInfoIfNoneExists(Object *obj);
+  Object createDocInfoIfNoneExists();
 
   // Remove the document's Info dictionary and update the trailer dictionary.
   void removeDocInfo();
@@ -271,11 +271,11 @@
   // XRefWriter subclass that writes a XRef stream
   class XRefStreamWriter: public XRefWriter {
   public:
-    XRefStreamWriter(Object *index, GooString *stmBuf, int offsetSize);
+    XRefStreamWriter(Array *index, GooString *stmBuf, int offsetSize);
     void startSection(int first, int count) override;
     void writeEntry(Goffset offset, int gen, XRefEntryType type) override;
   private:
-    Object *index;
+    Array *index;
     GooString *stmBuf;
     int offsetSize;
   };
diff --git a/qt4/src/poppler-annotation-helper.h b/qt4/src/poppler-annotation-helper.h
index 5f335c0..3150569 100644
--- a/qt4/src/poppler-annotation-helper.h
+++ b/qt4/src/poppler-annotation-helper.h
@@ -1,5 +1,5 @@
 /* poppler-annotation-helper.h: qt interface to poppler
- * Copyright (C) 2006, 2008, Albert Astals Cid <aacid@kde.org>
+ * Copyright (C) 2006, 2008, 2017, Albert Astals Cid <aacid@kde.org>
  * Copyright (C) 2008, Pino Toscano <pino@kde.org>
  * Copyright (C) 2012, Fabio D'Urso <fabiodurso@hotmail.it>
  * Adapting code from
@@ -50,83 +50,71 @@
 
 void XPDFReader::lookupName( Dict * dict, char * type, QString & dest )
 {
-    Object nameObj;
-    dict->lookup( type, &nameObj );
+    Object nameObj = dict->lookup( type );
     if ( nameObj.isNull() )
         return;
     if ( nameObj.isName() )
         dest = nameObj.getName();
     else
         qDebug() << type << " is not Name." << endl;
-    nameObj.free();
 }
 
 void XPDFReader::lookupString( Dict * dict, char * type, QString & dest )
 {
-    Object stringObj;
-    dict->lookup( type, &stringObj );
+    Object stringObj = dict->lookup( type );
     if ( stringObj.isNull() )
         return;
     if ( stringObj.isString() )
         dest = stringObj.getString()->getCString();
     else
         qDebug() << type << " is not String." << endl;
-    stringObj.free();
 }
 
 void XPDFReader::lookupBool( Dict * dict, char * type, bool & dest )
 {
-    Object boolObj;
-    dict->lookup( type, &boolObj );
+    Object boolObj = dict->lookup( type );
     if ( boolObj.isNull() )
         return;
     if ( boolObj.isBool() )
         dest = boolObj.getBool() == gTrue;
     else
         qDebug() << type << " is not Bool." << endl;
-    boolObj.free();
 }
 
 void XPDFReader::lookupInt( Dict * dict, char * type, int & dest )
 {
-    Object intObj;
-    dict->lookup( type, &intObj );
+    Object intObj = dict->lookup( type );
     if ( intObj.isNull() )
         return;
     if ( intObj.isInt() )
         dest = intObj.getInt();
     else
         qDebug() << type << " is not Int." << endl;
-    intObj.free();
 }
 
 void XPDFReader::lookupNum( Dict * dict, char * type, double & dest )
 {
-    Object numObj;
-    dict->lookup( type, &numObj );
+    Object numObj = dict->lookup( type );
     if ( numObj.isNull() )
         return;
     if ( numObj.isNum() )
         dest = numObj.getNum();
     else
         qDebug() << type << " is not Num." << endl;
-    numObj.free();
 }
 
 int XPDFReader::lookupNumArray( Dict * dict, char * type, double * dest, int len )
 {
-    Object arrObj;
-    dict->lookup( type, &arrObj );
+    Object arrObj = dict->lookup( type );
     if ( arrObj.isNull() )
         return 0;
-    Object numObj;
     if ( arrObj.isArray() )
     {
         len = qMin( len, arrObj.arrayGetLength() );
         for ( int i = 0; i < len; i++ )
         {
-            dest[i] = arrObj.arrayGet( i, &numObj )->getNum();
-            numObj.free();
+            Object numObj = arrObj.arrayGet( i );
+            dest[i] = numObj.getNum();
         }
     }
     else
@@ -134,7 +122,6 @@
         len = 0;
         qDebug() << type << "is not Array." << endl;
     }
-    arrObj.free();
     return len;
 }
 
@@ -147,21 +134,18 @@
 
 void XPDFReader::lookupIntRef( Dict * dict, char * type, int & dest )
 {
-    Object refObj;
-    dict->lookupNF( type, &refObj );
+    Object refObj = dict->lookupNF( type );
     if ( refObj.isNull() )
         return;
     if ( refObj.isRef() )
         dest = refObj.getRefNum();
     else
         qDebug() << type << " is not Ref." << endl;
-    refObj.free();
 }
 
 void XPDFReader::lookupDate( Dict * dict, char * type, QDateTime & dest )
 {
-    Object dateObj;
-    dict->lookup( type, &dateObj );
+    Object dateObj = dict->lookup( type );
     if ( dateObj.isNull() )
         return;
     if ( dateObj.isString() )
@@ -170,7 +154,6 @@
     }
     else
         qDebug() << type << " is not Date" << endl;
-    dateObj.free();
 }
 
 void XPDFReader::transform( double * M, double x, double y, QPointF &res )
diff --git a/qt4/src/poppler-document.cc b/qt4/src/poppler-document.cc
index 7f8abfa..f5ac11e 100644
--- a/qt4/src/poppler-document.cc
+++ b/qt4/src/poppler-document.cc
@@ -1,7 +1,7 @@
 /* poppler-document.cc: qt interface to poppler
  * Copyright (C) 2005, Net Integration Technologies, Inc.
  * Copyright (C) 2005, 2008, Brad Hards <bradh@frogmouth.net>
- * Copyright (C) 2005-2010, 2012, 2013, 2015, 2016, Albert Astals Cid <aacid@kde.org>
+ * Copyright (C) 2005-2010, 2012, 2013, 2015-2017, Albert Astals Cid <aacid@kde.org>
  * Copyright (C) 2006-2010, Pino Toscano <pino@kde.org>
  * Copyright (C) 2010, 2011 Hib Eris <hib@hiberis.nl>
  * Copyright (C) 2012 Koji Otani <sho@bbr.jp>
@@ -257,12 +257,10 @@
 	QByteArray result;
 	if (fi.isEmbedded())
 	{
-		Object refObj, strObj;
 		XRef *xref = m_doc->doc->getXRef()->copy();
 
-		refObj.initRef(fi.m_data->embRef.num, fi.m_data->embRef.gen);
-		refObj.fetch(xref, &strObj);
-		refObj.free();
+		Object refObj(fi.m_data->embRef.num, fi.m_data->embRef.gen);
+		Object strObj = refObj.fetch(xref);
 		if (strObj.isStream())
 		{
 			int c;
@@ -273,7 +271,6 @@
 			}
 			strObj.streamClose();
 		}
-		strObj.free();
 		delete xref;
 	}
 	return result;
@@ -434,14 +431,13 @@
     {
 	QStringList keys;
 
-	Object info;
 	if ( m_doc->locked )
 	    return QStringList();
 
 	QScopedPointer<XRef> xref(m_doc->doc->getXRef()->copy());
 	if (!xref)
 		return QStringList();
-	xref->getDocInfo(&info);
+	Object info = xref->getDocInfo();
 	if ( !info.isDict() )
 	    return QStringList();
 
@@ -452,7 +448,6 @@
 	    keys.append( QString::fromAscii(infoDict->getKey(i)) );
 	}
 
-	info.free();
 	return keys;
     }
 
diff --git a/qt4/src/poppler-form.cc b/qt4/src/poppler-form.cc
index 12aa329..57cde57 100644
--- a/qt4/src/poppler-form.cc
+++ b/qt4/src/poppler-form.cc
@@ -1,6 +1,6 @@
 /* poppler-form.h: qt4 interface to poppler
  * Copyright (C) 2007-2008, 2011, Pino Toscano <pino@kde.org>
- * Copyright (C) 2008, 2011, 2012, 2015, Albert Astals Cid <aacid@kde.org>
+ * Copyright (C) 2008, 2011, 2012, 2015, 2017, Albert Astals Cid <aacid@kde.org>
  * Copyright (C) 2011 Carlos Garcia Campos <carlosgc@gnome.org>
  * Copyright (C) 2012, Adam Reichold <adamreichold@myopera.com>
  *
@@ -191,8 +191,8 @@
   if (fwb->getButtonType() == formButtonPush)
   {
     Dict *dict = m_formData->fm->getObj()->getDict();
-    Object obj1;
-    if (dict->lookup("MK", &obj1)->isDict())
+    Object obj1 = dict->lookup("MK");
+    if (obj1.isDict())
     {
       AnnotAppearanceCharacs appearCharacs(obj1.getDict());
       if (appearCharacs.getNormalCaption())
@@ -200,7 +200,6 @@
         ret = UnicodeParsedString(appearCharacs.getNormalCaption());
       }
     }
-    obj1.free();
   }
   else
   {
diff --git a/qt4/src/poppler-optcontent.cc b/qt4/src/poppler-optcontent.cc
index a5b651a..0e7b534 100644
--- a/qt4/src/poppler-optcontent.cc
+++ b/qt4/src/poppler-optcontent.cc
@@ -3,7 +3,7 @@
  * Copyright (C) 2007, Brad Hards <bradh@kde.org>
  * Copyright (C) 2008, 2014, Pino Toscano <pino@kde.org>
  * Copyright (C) 2008, Carlos Garcia Campos <carlosgc@gnome.org>
- * Copyright (C) 2015, 2016, Albert Astals Cid <aacid@kde.org>
+ * Copyright (C) 2015-2017, Albert Astals Cid <aacid@kde.org>
  * Copyright (C) 2017, Hubert Figuière <hub@figuiere.net>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -41,8 +41,7 @@
   {
     itemsInGroup.reserve( rbarray->getLength() );
     for (int i = 0; i < rbarray->getLength(); ++i) {
-      Object ref;
-      rbarray->getNF( i, &ref );
+      Object ref = rbarray->getNF( i );
       if ( ! ref.isRef() ) {
 	qDebug() << "expected ref, but got:" << ref.getType();
       }
@@ -199,11 +198,9 @@
   {
     OptContentItem *lastItem = parentNode;
     for (int i = 0; i < orderArray->getLength(); ++i) {
-      Object orderItem;
-      orderArray->get(i, &orderItem);
+      Object orderItem = orderArray->get(i);
       if ( orderItem.isDict() ) {
-	Object item;
-	orderArray->getNF(i, &item);
+	Object item = orderArray->getNF(i);
 	if (item.isRef() ) {
           OptContentItem *ocItem = m_optContentItems.value(QString::number(item.getRefNum()), 0);
 	  if (ocItem) {
@@ -213,7 +210,6 @@
             qDebug() << "could not find group for object" << item.getRefNum();
 	  }
 	}
-	item.free();
       } else if ( (orderItem.isArray()) && (orderItem.arrayGetLength() > 0) ) {
 	parseOrderArray(lastItem, orderItem.getArray());
       } else if ( orderItem.isString() ) {
@@ -226,7 +222,6 @@
       } else {
 	qDebug() << "something unexpected";
       }	
-      orderItem.free();
     }
   }
 
@@ -237,8 +232,7 @@
     }
     // This is an array of array(s)
     for (int i = 0; i < rBGroupArray->getLength(); ++i) {
-      Object rbObj;
-      rBGroupArray->get(i, &rbObj);
+      Object rbObj = rBGroupArray->get(i);
       if ( ! rbObj.isArray() ) {
 	qDebug() << "expected inner array, got:" << rbObj.getType();
 	return;
@@ -246,7 +240,6 @@
       Array *rbarray = rbObj.getArray();
       RadioButtonGroup *rbg = new RadioButtonGroup( this, rbarray );
       m_rbgroups.append( rbg );
-      rbObj.free();
     }
   }
 
diff --git a/qt4/src/poppler-page.cc b/qt4/src/poppler-page.cc
index fb6a036..1a55bb5 100644
--- a/qt4/src/poppler-page.cc
+++ b/qt4/src/poppler-page.cc
@@ -1,7 +1,7 @@
 /* poppler-page.cc: qt interface to poppler
  * Copyright (C) 2005, Net Integration Technologies, Inc.
  * Copyright (C) 2005, Brad Hards <bradh@frogmouth.net>
- * Copyright (C) 2005-2016, Albert Astals Cid <aacid@kde.org>
+ * Copyright (C) 2005-2017, Albert Astals Cid <aacid@kde.org>
  * Copyright (C) 2005, Stefan Kebekus <stefan.kebekus@math.uni-koeln.de>
  * Copyright (C) 2006-2011, Pino Toscano <pino@kde.org>
  * Copyright (C) 2008 Carlos Garcia Campos <carlosgc@gnome.org>
@@ -650,11 +650,10 @@
 PageTransition *Page::transition() const
 {
   if (!m_page->transition) {
-    Object o;
     PageTransitionParams params;
-    params.dictObj = m_page->page->getTrans(&o);
-    if (params.dictObj->isDict()) m_page->transition = new PageTransition(params);
-    o.free();
+    Object o = m_page->page->getTrans();
+    params.dictObj = &o;
+    if (o.isDict()) m_page->transition = new PageTransition(params);
   }
   return m_page->transition;
 }
@@ -663,20 +662,15 @@
 {
   if ( act == Page::Opening || act == Page::Closing )
   {
-    Object o;
-    m_page->page->getActions(&o);
+    Object o = m_page->page->getActions();
     if (!o.isDict())
     {
-      o.free();
       return 0;
     }
     Dict *dict = o.getDict();
-    Object o2;
     const char *key = act == Page::Opening ? "O" : "C";
-    dict->lookup((char*)key, &o2);
+    Object o2 = dict->lookup((char*)key);
     ::LinkAction *lact = ::LinkAction::parseAction(&o2, m_page->parentDoc->doc->getCatalog()->getBaseURI() );
-    o2.free();
-    o.free();
     Link *popplerLink = NULL;
     if (lact != NULL)
     {
diff --git a/qt4/src/poppler-private.h b/qt4/src/poppler-private.h
index 0c0731c..a5ad3f3 100644
--- a/qt4/src/poppler-private.h
+++ b/qt4/src/poppler-private.h
@@ -1,7 +1,7 @@
 /* poppler-private.h: qt interface to poppler
  * Copyright (C) 2005, Net Integration Technologies, Inc.
  * Copyright (C) 2005, 2008, Brad Hards <bradh@frogmouth.net>
- * Copyright (C) 2006-2009, 2011, 2012 by Albert Astals Cid <aacid@kde.org>
+ * Copyright (C) 2006-2009, 2011, 2012, 2017 by Albert Astals Cid <aacid@kde.org>
  * Copyright (C) 2007-2009, 2011 by Pino Toscano <pino@kde.org>
  * Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com>
  * Copyright (C) 2011 Hib Eris <hib@hiberis.nl>
@@ -103,10 +103,8 @@
 	
 	DocumentData(const QByteArray &data, GooString *ownerPassword, GooString *userPassword)
 	    {
-		Object obj;
 		fileContents = data;
-		obj.initNull();
-		MemStream *str = new MemStream((char*)fileContents.data(), 0, fileContents.length(), &obj);
+		MemStream *str = new MemStream((char*)fileContents.data(), 0, fileContents.length(), Object(objNull));
 		init();
 		doc = new PDFDoc(str, ownerPassword, userPassword);
 		delete ownerPassword;
diff --git a/qt4/tests/check_lexer.cpp b/qt4/tests/check_lexer.cpp
index 243a592..93c3621 100644
--- a/qt4/tests/check_lexer.cpp
+++ b/qt4/tests/check_lexer.cpp
@@ -13,112 +13,91 @@
 void TestLexer::testNumbers()
 {
     char data[] = "0 1 -1 2147483647 -2147483647 2147483648 -2147483648 4294967297 -2147483649 0.1 1.1 -1.1 2147483647.1 -2147483647.1 2147483648.1 -2147483648.1 4294967297.1 -2147483649.1 9223372036854775807 18446744073709551615";
-    Object dummy;
-    MemStream *stream = new MemStream(data, 0, strlen(data), &dummy);
+    MemStream *stream = new MemStream(data, 0, strlen(data), Object(objNull));
     Lexer *lexer = new Lexer(NULL, stream);
     QVERIFY( lexer );
     
     Object obj;
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), 0);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), 1);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), -1);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), 2147483647);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), -2147483647);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt64);
     QCOMPARE(obj.getInt64(), 2147483648ll);
-    obj.free();
       
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), -2147483647-1);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt64);
     QCOMPARE(obj.getInt64(), 4294967297ll);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt64);
     QCOMPARE(obj.getInt64(), -2147483649ll);
-    obj.free();
 
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 0.1);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 1.1);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), -1.1);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 2147483647.1);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), -2147483647.1);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 2147483648.1);
-    obj.free();
       
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), -2147483648.1);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 4294967297.1);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), -2147483649.1);
-    obj.free();
 
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt64);
     QCOMPARE(obj.getInt64(), 9223372036854775807ll);
-    obj.free();
 
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 18446744073709551616.);
-    obj.free();
 
     delete lexer;
 }
diff --git a/qt4/tests/check_optcontent.cpp b/qt4/tests/check_optcontent.cpp
index 22b14a4..2de2995 100644
--- a/qt4/tests/check_optcontent.cpp
+++ b/qt4/tests/check_optcontent.cpp
@@ -101,66 +101,57 @@
 
     // AnyOn, one element array:
     // 22 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOn>>endobj
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QVERIFY( ocgs->optContentIsVisible( &obj ) );
-    obj.free();
 
     // Same again, looking for any leaks or dubious free()'s
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QVERIFY( ocgs->optContentIsVisible( &obj ) );
-    obj.free();
 
     // AnyOff, one element array:
     // 29 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOff>>endobj
-    xref->fetch( 29, 0, &obj );
+    obj = xref->fetch( 29, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOn, one element array:
     // 36 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOn>>endobj
-    xref->fetch( 36, 0, &obj );
+    obj = xref->fetch( 36, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
 
     // AllOff, one element array:
     // 43 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOff>>endobj
-    xref->fetch( 43, 0, &obj );
+    obj = xref->fetch( 43, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AnyOn, multi-element array:
     // 50 0 obj<</Type/OCMD/OCGs[21 0 R 28 0 R]/P/AnyOn>>endobj
-    xref->fetch( 50, 0, &obj );
+    obj = xref->fetch( 50, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOff, multi-element array:
     // 57 0 obj<</Type/OCMD/P/AnyOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 57, 0, &obj );
+    obj = xref->fetch( 57, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOn, multi-element array:
     // 64 0 obj<</Type/OCMD/P/AllOn/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 64, 0, &obj );
+    obj = xref->fetch( 64, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOff, multi-element array:
     // 71 0 obj<</Type/OCMD/P/AllOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 71, 0, &obj );
+    obj = xref->fetch( 71, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     delete doc;
     delete globalParams;
@@ -182,8 +173,7 @@
 
     // In this test, both Ref(21,0) and Ref(28,0) start On,
     // based on the file settings
-    Object ref21obj;
-    ref21obj.initRef( 21, 0 );
+    Object ref21obj( 21, 0 );
     Ref ref21 = ref21obj.getRef();
     OptionalContentGroup *ocgA = ocgs->findOcgByRef( ref21 );
     QVERIFY( ocgA );
@@ -191,8 +181,7 @@
     QVERIFY( (ocgA->getName()->cmp("A")) == 0 );
     QCOMPARE( ocgA->getState(), OptionalContentGroup::On );
 
-    Object ref28obj;
-    ref28obj.initRef( 28, 0 );
+    Object ref28obj( 28, 0 );
     Ref ref28 = ref28obj.getRef();
     OptionalContentGroup *ocgB = ocgs->findOcgByRef( ref28 );
     QVERIFY( ocgB );
@@ -205,65 +194,56 @@
 
     // AnyOn, one element array:
     // 22 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOn>>endobj
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // Same again, looking for any leaks or dubious free()'s
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AnyOff, one element array:
     // 29 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOff>>endobj
-    xref->fetch( 29, 0, &obj );
+    obj = xref->fetch( 29, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOn, one element array:
     // 36 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOn>>endobj
-    xref->fetch( 36, 0, &obj );
+    obj = xref->fetch( 36, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOff, one element array:
     // 43 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOff>>endobj
-    xref->fetch( 43, 0, &obj );
+    obj = xref->fetch( 43, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AnyOn, multi-element array:
     // 50 0 obj<</Type/OCMD/OCGs[21 0 R 28 0 R]/P/AnyOn>>endobj
-    xref->fetch( 50, 0, &obj );
+    obj = xref->fetch( 50, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOff, multi-element array:
     // 57 0 obj<</Type/OCMD/P/AnyOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 57, 0, &obj );
+    obj = xref->fetch( 57, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOn, multi-element array:
     // 64 0 obj<</Type/OCMD/P/AllOn/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 64, 0, &obj );
+    obj = xref->fetch( 64, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOff, multi-element array:
     // 71 0 obj<</Type/OCMD/P/AllOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 71, 0, &obj );
+    obj = xref->fetch( 71, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
 
     // Turn the other one off as well (i.e. both are Off)
@@ -271,65 +251,56 @@
 
     // AnyOn, one element array:
     // 22 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOn>>endobj
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // Same again, looking for any leaks or dubious free()'s
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AnyOff, one element array:
     // 29 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOff>>endobj
-    xref->fetch( 29, 0, &obj );
+    obj = xref->fetch( 29, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOn, one element array:
     // 36 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOn>>endobj
-    xref->fetch( 36, 0, &obj );
+    obj = xref->fetch( 36, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOff, one element array:
     // 43 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOff>>endobj
-    xref->fetch( 43, 0, &obj );
+    obj = xref->fetch( 43, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOn, multi-element array:
     // 50 0 obj<</Type/OCMD/OCGs[21 0 R 28 0 R]/P/AnyOn>>endobj
-    xref->fetch( 50, 0, &obj );
+    obj = xref->fetch( 50, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AnyOff, multi-element array:
     // 57 0 obj<</Type/OCMD/P/AnyOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 57, 0, &obj );
+    obj = xref->fetch( 57, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOn, multi-element array:
     // 64 0 obj<</Type/OCMD/P/AllOn/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 64, 0, &obj );
+    obj = xref->fetch( 64, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOff, multi-element array:
     // 71 0 obj<</Type/OCMD/P/AllOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 71, 0, &obj );
+    obj = xref->fetch( 71, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
 
     // Turn the first one on again (21 is On, 28 is Off)
@@ -337,65 +308,56 @@
 
     // AnyOn, one element array:
     // 22 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOn>>endobj
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // Same again, looking for any leaks or dubious free()'s
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOff, one element array:
     // 29 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOff>>endobj
-    xref->fetch( 29, 0, &obj );
+    obj = xref->fetch( 29, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOn, one element array:
     // 36 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOn>>endobj
-    xref->fetch( 36, 0, &obj );
+    obj = xref->fetch( 36, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOff, one element array:
     // 43 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOff>>endobj
-    xref->fetch( 43, 0, &obj );
+    obj = xref->fetch( 43, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOn, multi-element array:
     // 50 0 obj<</Type/OCMD/OCGs[21 0 R 28 0 R]/P/AnyOn>>endobj
-    xref->fetch( 50, 0, &obj );
+    obj = xref->fetch( 50, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOff, multi-element array:
     // 57 0 obj<</Type/OCMD/P/AnyOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 57, 0, &obj );
+    obj = xref->fetch( 57, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOn, multi-element array:
     // 64 0 obj<</Type/OCMD/P/AllOn/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 64, 0, &obj );
+    obj = xref->fetch( 64, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOff, multi-element array:
     // 71 0 obj<</Type/OCMD/P/AllOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 71, 0, &obj );
+    obj = xref->fetch( 71, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     delete doc;
     delete globalParams;
diff --git a/qt5/src/poppler-annotation-helper.h b/qt5/src/poppler-annotation-helper.h
index 5f335c0..3150569 100644
--- a/qt5/src/poppler-annotation-helper.h
+++ b/qt5/src/poppler-annotation-helper.h
@@ -1,5 +1,5 @@
 /* poppler-annotation-helper.h: qt interface to poppler
- * Copyright (C) 2006, 2008, Albert Astals Cid <aacid@kde.org>
+ * Copyright (C) 2006, 2008, 2017, Albert Astals Cid <aacid@kde.org>
  * Copyright (C) 2008, Pino Toscano <pino@kde.org>
  * Copyright (C) 2012, Fabio D'Urso <fabiodurso@hotmail.it>
  * Adapting code from
@@ -50,83 +50,71 @@
 
 void XPDFReader::lookupName( Dict * dict, char * type, QString & dest )
 {
-    Object nameObj;
-    dict->lookup( type, &nameObj );
+    Object nameObj = dict->lookup( type );
     if ( nameObj.isNull() )
         return;
     if ( nameObj.isName() )
         dest = nameObj.getName();
     else
         qDebug() << type << " is not Name." << endl;
-    nameObj.free();
 }
 
 void XPDFReader::lookupString( Dict * dict, char * type, QString & dest )
 {
-    Object stringObj;
-    dict->lookup( type, &stringObj );
+    Object stringObj = dict->lookup( type );
     if ( stringObj.isNull() )
         return;
     if ( stringObj.isString() )
         dest = stringObj.getString()->getCString();
     else
         qDebug() << type << " is not String." << endl;
-    stringObj.free();
 }
 
 void XPDFReader::lookupBool( Dict * dict, char * type, bool & dest )
 {
-    Object boolObj;
-    dict->lookup( type, &boolObj );
+    Object boolObj = dict->lookup( type );
     if ( boolObj.isNull() )
         return;
     if ( boolObj.isBool() )
         dest = boolObj.getBool() == gTrue;
     else
         qDebug() << type << " is not Bool." << endl;
-    boolObj.free();
 }
 
 void XPDFReader::lookupInt( Dict * dict, char * type, int & dest )
 {
-    Object intObj;
-    dict->lookup( type, &intObj );
+    Object intObj = dict->lookup( type );
     if ( intObj.isNull() )
         return;
     if ( intObj.isInt() )
         dest = intObj.getInt();
     else
         qDebug() << type << " is not Int." << endl;
-    intObj.free();
 }
 
 void XPDFReader::lookupNum( Dict * dict, char * type, double & dest )
 {
-    Object numObj;
-    dict->lookup( type, &numObj );
+    Object numObj = dict->lookup( type );
     if ( numObj.isNull() )
         return;
     if ( numObj.isNum() )
         dest = numObj.getNum();
     else
         qDebug() << type << " is not Num." << endl;
-    numObj.free();
 }
 
 int XPDFReader::lookupNumArray( Dict * dict, char * type, double * dest, int len )
 {
-    Object arrObj;
-    dict->lookup( type, &arrObj );
+    Object arrObj = dict->lookup( type );
     if ( arrObj.isNull() )
         return 0;
-    Object numObj;
     if ( arrObj.isArray() )
     {
         len = qMin( len, arrObj.arrayGetLength() );
         for ( int i = 0; i < len; i++ )
         {
-            dest[i] = arrObj.arrayGet( i, &numObj )->getNum();
-            numObj.free();
+            Object numObj = arrObj.arrayGet( i );
+            dest[i] = numObj.getNum();
         }
     }
     else
@@ -134,7 +122,6 @@
         len = 0;
         qDebug() << type << "is not Array." << endl;
     }
-    arrObj.free();
     return len;
 }
 
@@ -147,21 +134,18 @@
 
 void XPDFReader::lookupIntRef( Dict * dict, char * type, int & dest )
 {
-    Object refObj;
-    dict->lookupNF( type, &refObj );
+    Object refObj = dict->lookupNF( type );
     if ( refObj.isNull() )
         return;
     if ( refObj.isRef() )
         dest = refObj.getRefNum();
     else
         qDebug() << type << " is not Ref." << endl;
-    refObj.free();
 }
 
 void XPDFReader::lookupDate( Dict * dict, char * type, QDateTime & dest )
 {
-    Object dateObj;
-    dict->lookup( type, &dateObj );
+    Object dateObj = dict->lookup( type );
     if ( dateObj.isNull() )
         return;
     if ( dateObj.isString() )
@@ -170,7 +154,6 @@
     }
     else
         qDebug() << type << " is not Date" << endl;
-    dateObj.free();
 }
 
 void XPDFReader::transform( double * M, double x, double y, QPointF &res )
diff --git a/qt5/src/poppler-document.cc b/qt5/src/poppler-document.cc
index 741a1b7..b326187 100644
--- a/qt5/src/poppler-document.cc
+++ b/qt5/src/poppler-document.cc
@@ -243,12 +243,10 @@
 	QByteArray result;
 	if (fi.isEmbedded())
 	{
-		Object refObj, strObj;
 		XRef *xref = m_doc->doc->getXRef()->copy();
 
-		refObj.initRef(fi.m_data->embRef.num, fi.m_data->embRef.gen);
-		refObj.fetch(xref, &strObj);
-		refObj.free();
+		Object refObj(fi.m_data->embRef.num, fi.m_data->embRef.gen);
+		Object strObj = refObj.fetch(xref);
 		if (strObj.isStream())
 		{
 			int c;
@@ -259,7 +257,6 @@
 			}
 			strObj.streamClose();
 		}
-		strObj.free();
 		delete xref;
 	}
 	return result;
@@ -420,14 +417,13 @@
     {
 	QStringList keys;
 
-	Object info;
 	if ( m_doc->locked )
 	    return QStringList();
 
 	QScopedPointer<XRef> xref(m_doc->doc->getXRef()->copy());
 	if (!xref)
 		return QStringList();
-	xref->getDocInfo(&info);
+	Object info = xref->getDocInfo();
 	if ( !info.isDict() )
 	    return QStringList();
 
@@ -438,7 +434,6 @@
 	    keys.append( QString::fromLatin1(infoDict->getKey(i)) );
 	}
 
-	info.free();
 	return keys;
     }
 
diff --git a/qt5/src/poppler-form.cc b/qt5/src/poppler-form.cc
index 1ccb26c..6cbceb0 100644
--- a/qt5/src/poppler-form.cc
+++ b/qt5/src/poppler-form.cc
@@ -220,8 +220,8 @@
   if (fwb->getButtonType() == formButtonPush)
   {
     Dict *dict = m_formData->fm->getObj()->getDict();
-    Object obj1;
-    if (dict->lookup("MK", &obj1)->isDict())
+    Object obj1 = dict->lookup("MK");
+    if (obj1.isDict())
     {
       AnnotAppearanceCharacs appearCharacs(obj1.getDict());
       if (appearCharacs.getNormalCaption())
@@ -229,7 +229,6 @@
         ret = UnicodeParsedString(appearCharacs.getNormalCaption());
       }
     }
-    obj1.free();
   }
   else
   {
diff --git a/qt5/src/poppler-optcontent.cc b/qt5/src/poppler-optcontent.cc
index 15ba650..805d896 100644
--- a/qt5/src/poppler-optcontent.cc
+++ b/qt5/src/poppler-optcontent.cc
@@ -3,7 +3,7 @@
  * Copyright (C) 2007, Brad Hards <bradh@kde.org>
  * Copyright (C) 2008, 2014, Pino Toscano <pino@kde.org>
  * Copyright (C) 2008, Carlos Garcia Campos <carlosgc@gnome.org>
- * Copyright (C) 2015, 2016, Albert Astals Cid <aacid@kde.org>
+ * Copyright (C) 2015-2017, Albert Astals Cid <aacid@kde.org>
  * Copyright (C) 2017, Hubert Figuière <hub@figuiere.net>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -41,8 +41,7 @@
   {
     itemsInGroup.reserve(rbarray->getLength());
     for (int i = 0; i < rbarray->getLength(); ++i) {
-      Object ref;
-      rbarray->getNF( i, &ref );
+      Object ref = rbarray->getNF( i );
       if ( ! ref.isRef() ) {
 	qDebug() << "expected ref, but got:" << ref.getType();
       }
@@ -199,11 +198,9 @@
   {
     OptContentItem *lastItem = parentNode;
     for (int i = 0; i < orderArray->getLength(); ++i) {
-      Object orderItem;
-      orderArray->get(i, &orderItem);
+      Object orderItem = orderArray->get(i);
       if ( orderItem.isDict() ) {
-	Object item;
-	orderArray->getNF(i, &item);
+	Object item = orderArray->getNF(i);
 	if (item.isRef() ) {
           OptContentItem *ocItem = m_optContentItems.value(QString::number(item.getRefNum()), 0);
 	  if (ocItem) {
@@ -213,7 +210,6 @@
             qDebug() << "could not find group for object" << item.getRefNum();
 	  }
 	}
-	item.free();
       } else if ( (orderItem.isArray()) && (orderItem.arrayGetLength() > 0) ) {
 	parseOrderArray(lastItem, orderItem.getArray());
       } else if ( orderItem.isString() ) {
@@ -226,7 +222,6 @@
       } else {
 	qDebug() << "something unexpected";
       }	
-      orderItem.free();
     }
   }
 
@@ -237,8 +232,7 @@
     }
     // This is an array of array(s)
     for (int i = 0; i < rBGroupArray->getLength(); ++i) {
-      Object rbObj;
-      rBGroupArray->get(i, &rbObj);
+      Object rbObj = rBGroupArray->get(i);
       if ( ! rbObj.isArray() ) {
 	qDebug() << "expected inner array, got:" << rbObj.getType();
 	return;
@@ -246,7 +240,6 @@
       Array *rbarray = rbObj.getArray();
       RadioButtonGroup *rbg = new RadioButtonGroup( this, rbarray );
       m_rbgroups.append( rbg );
-      rbObj.free();
     }
   }
 
diff --git a/qt5/src/poppler-page.cc b/qt5/src/poppler-page.cc
index 4e35a36..0bba618 100644
--- a/qt5/src/poppler-page.cc
+++ b/qt5/src/poppler-page.cc
@@ -1,7 +1,7 @@
 /* poppler-page.cc: qt interface to poppler
  * Copyright (C) 2005, Net Integration Technologies, Inc.
  * Copyright (C) 2005, Brad Hards <bradh@frogmouth.net>
- * Copyright (C) 2005-2016, Albert Astals Cid <aacid@kde.org>
+ * Copyright (C) 2005-2017, Albert Astals Cid <aacid@kde.org>
  * Copyright (C) 2005, Stefan Kebekus <stefan.kebekus@math.uni-koeln.de>
  * Copyright (C) 2006-2011, Pino Toscano <pino@kde.org>
  * Copyright (C) 2008 Carlos Garcia Campos <carlosgc@gnome.org>
@@ -633,11 +633,10 @@
 PageTransition *Page::transition() const
 {
   if (!m_page->transition) {
-    Object o;
+    Object o = m_page->page->getTrans();
     PageTransitionParams params;
-    params.dictObj = m_page->page->getTrans(&o);
+    params.dictObj = &o;
     if (params.dictObj->isDict()) m_page->transition = new PageTransition(params);
-    o.free();
   }
   return m_page->transition;
 }
@@ -646,20 +645,15 @@
 {
   if ( act == Page::Opening || act == Page::Closing )
   {
-    Object o;
-    m_page->page->getActions(&o);
+    Object o = m_page->page->getActions();
     if (!o.isDict())
     {
-      o.free();
       return 0;
     }
     Dict *dict = o.getDict();
-    Object o2;
     const char *key = act == Page::Opening ? "O" : "C";
-    dict->lookup((char*)key, &o2);
+    Object o2 = dict->lookup((char*)key);
     ::LinkAction *lact = ::LinkAction::parseAction(&o2, m_page->parentDoc->doc->getCatalog()->getBaseURI() );
-    o2.free();
-    o.free();
     Link *popplerLink = NULL;
     if (lact != NULL)
     {
diff --git a/qt5/src/poppler-private.h b/qt5/src/poppler-private.h
index 9afcc84..6d0d194 100644
--- a/qt5/src/poppler-private.h
+++ b/qt5/src/poppler-private.h
@@ -1,7 +1,7 @@
 /* poppler-private.h: qt interface to poppler
  * Copyright (C) 2005, Net Integration Technologies, Inc.
  * Copyright (C) 2005, 2008, Brad Hards <bradh@frogmouth.net>
- * Copyright (C) 2006-2009, 2011, 2012 by Albert Astals Cid <aacid@kde.org>
+ * Copyright (C) 2006-2009, 2011, 2012, 2017 by Albert Astals Cid <aacid@kde.org>
  * Copyright (C) 2007-2009, 2011, 2014 by Pino Toscano <pino@kde.org>
  * Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com>
  * Copyright (C) 2011 Hib Eris <hib@hiberis.nl>
@@ -103,10 +103,8 @@
 	
 	DocumentData(const QByteArray &data, GooString *ownerPassword, GooString *userPassword)
 	    {
-		Object obj;
 		fileContents = data;
-		obj.initNull();
-		MemStream *str = new MemStream((char*)fileContents.data(), 0, fileContents.length(), &obj);
+		MemStream *str = new MemStream((char*)fileContents.data(), 0, fileContents.length(), Object(objNull));
 		init();
 		doc = new PDFDoc(str, ownerPassword, userPassword);
 		delete ownerPassword;
diff --git a/qt5/tests/check_lexer.cpp b/qt5/tests/check_lexer.cpp
index 243a592..4453e90 100644
--- a/qt5/tests/check_lexer.cpp
+++ b/qt5/tests/check_lexer.cpp
@@ -13,112 +13,91 @@
 void TestLexer::testNumbers()
 {
     char data[] = "0 1 -1 2147483647 -2147483647 2147483648 -2147483648 4294967297 -2147483649 0.1 1.1 -1.1 2147483647.1 -2147483647.1 2147483648.1 -2147483648.1 4294967297.1 -2147483649.1 9223372036854775807 18446744073709551615";
-    Object dummy;
-    MemStream *stream = new MemStream(data, 0, strlen(data), &dummy);
+    MemStream *stream = new MemStream(data, 0, strlen(data), Object(objNull));
     Lexer *lexer = new Lexer(NULL, stream);
     QVERIFY( lexer );
     
     Object obj;
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), 0);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), 1);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), -1);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), 2147483647);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), -2147483647);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt64);
     QCOMPARE(obj.getInt64(), 2147483648ll);
-    obj.free();
       
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), -2147483647-1);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt64);
     QCOMPARE(obj.getInt64(), 4294967297ll);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt64);
     QCOMPARE(obj.getInt64(), -2147483649ll);
-    obj.free();
 
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 0.1);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 1.1);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), -1.1);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 2147483647.1);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), -2147483647.1);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 2147483648.1);
-    obj.free();
       
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), -2147483648.1);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 4294967297.1);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), -2147483649.1);
-    obj.free();
 
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt64);
     QCOMPARE(obj.getInt64(), 9223372036854775807ll);
-    obj.free();
 
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 18446744073709551616.);
-    obj.free();
 
     delete lexer;
 }
diff --git a/qt5/tests/check_optcontent.cpp b/qt5/tests/check_optcontent.cpp
index cac1b43..32af227 100644
--- a/qt5/tests/check_optcontent.cpp
+++ b/qt5/tests/check_optcontent.cpp
@@ -101,66 +101,57 @@
 
     // AnyOn, one element array:
     // 22 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOn>>endobj
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QVERIFY( ocgs->optContentIsVisible( &obj ) );
-    obj.free();
 
     // Same again, looking for any leaks or dubious free()'s
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QVERIFY( ocgs->optContentIsVisible( &obj ) );
-    obj.free();
 
     // AnyOff, one element array:
     // 29 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOff>>endobj
-    xref->fetch( 29, 0, &obj );
+    obj = xref->fetch( 29, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOn, one element array:
     // 36 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOn>>endobj
-    xref->fetch( 36, 0, &obj );
+    obj = xref->fetch( 36, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
 
     // AllOff, one element array:
     // 43 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOff>>endobj
-    xref->fetch( 43, 0, &obj );
+    obj = xref->fetch( 43, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AnyOn, multi-element array:
     // 50 0 obj<</Type/OCMD/OCGs[21 0 R 28 0 R]/P/AnyOn>>endobj
-    xref->fetch( 50, 0, &obj );
+    obj = xref->fetch( 50, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOff, multi-element array:
     // 57 0 obj<</Type/OCMD/P/AnyOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 57, 0, &obj );
+    obj = xref->fetch( 57, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOn, multi-element array:
     // 64 0 obj<</Type/OCMD/P/AllOn/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 64, 0, &obj );
+    obj = xref->fetch( 64, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOff, multi-element array:
     // 71 0 obj<</Type/OCMD/P/AllOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 71, 0, &obj );
+    obj = xref->fetch( 71, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     delete doc;
     delete globalParams;
@@ -182,8 +173,7 @@
 
     // In this test, both Ref(21,0) and Ref(28,0) start On,
     // based on the file settings
-    Object ref21obj;
-    ref21obj.initRef( 21, 0 );
+    Object ref21obj( 21, 0 );
     Ref ref21 = ref21obj.getRef();
     OptionalContentGroup *ocgA = ocgs->findOcgByRef( ref21 );
     QVERIFY( ocgA );
@@ -191,8 +181,7 @@
     QVERIFY( (ocgA->getName()->cmp("A")) == 0 );
     QCOMPARE( ocgA->getState(), OptionalContentGroup::On );
 
-    Object ref28obj;
-    ref28obj.initRef( 28, 0 );
+    Object ref28obj( 28, 0 );
     Ref ref28 = ref28obj.getRef();
     OptionalContentGroup *ocgB = ocgs->findOcgByRef( ref28 );
     QVERIFY( ocgB );
@@ -205,65 +194,56 @@
 
     // AnyOn, one element array:
     // 22 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOn>>endobj
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // Same again, looking for any leaks or dubious free()'s
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AnyOff, one element array:
     // 29 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOff>>endobj
-    xref->fetch( 29, 0, &obj );
+    obj = xref->fetch( 29, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOn, one element array:
     // 36 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOn>>endobj
-    xref->fetch( 36, 0, &obj );
+    obj = xref->fetch( 36, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOff, one element array:
     // 43 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOff>>endobj
-    xref->fetch( 43, 0, &obj );
+    obj = xref->fetch( 43, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AnyOn, multi-element array:
     // 50 0 obj<</Type/OCMD/OCGs[21 0 R 28 0 R]/P/AnyOn>>endobj
-    xref->fetch( 50, 0, &obj );
+    obj = xref->fetch( 50, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOff, multi-element array:
     // 57 0 obj<</Type/OCMD/P/AnyOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 57, 0, &obj );
+    obj = xref->fetch( 57, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOn, multi-element array:
     // 64 0 obj<</Type/OCMD/P/AllOn/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 64, 0, &obj );
+    obj = xref->fetch( 64, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOff, multi-element array:
     // 71 0 obj<</Type/OCMD/P/AllOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 71, 0, &obj );
+    obj = xref->fetch( 71, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
 
     // Turn the other one off as well (i.e. both are Off)
@@ -271,65 +251,56 @@
 
     // AnyOn, one element array:
     // 22 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOn>>endobj
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // Same again, looking for any leaks or dubious free()'s
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AnyOff, one element array:
     // 29 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOff>>endobj
-    xref->fetch( 29, 0, &obj );
+    obj = xref->fetch( 29, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOn, one element array:
     // 36 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOn>>endobj
-    xref->fetch( 36, 0, &obj );
+    obj = xref->fetch( 36, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOff, one element array:
     // 43 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOff>>endobj
-    xref->fetch( 43, 0, &obj );
+    obj = xref->fetch( 43, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOn, multi-element array:
     // 50 0 obj<</Type/OCMD/OCGs[21 0 R 28 0 R]/P/AnyOn>>endobj
-    xref->fetch( 50, 0, &obj );
+    obj = xref->fetch( 50, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AnyOff, multi-element array:
     // 57 0 obj<</Type/OCMD/P/AnyOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 57, 0, &obj );
+    obj = xref->fetch( 57, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOn, multi-element array:
     // 64 0 obj<</Type/OCMD/P/AllOn/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 64, 0, &obj );
+    obj = xref->fetch( 64, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOff, multi-element array:
     // 71 0 obj<</Type/OCMD/P/AllOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 71, 0, &obj );
+    obj = xref->fetch( 71, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
 
     // Turn the first one on again (21 is On, 28 is Off)
@@ -337,65 +308,56 @@
 
     // AnyOn, one element array:
     // 22 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOn>>endobj
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // Same again, looking for any leaks or dubious free()'s
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOff, one element array:
     // 29 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOff>>endobj
-    xref->fetch( 29, 0, &obj );
+    obj = xref->fetch( 29, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOn, one element array:
     // 36 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOn>>endobj
-    xref->fetch( 36, 0, &obj );
+    obj = xref->fetch( 36, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOff, one element array:
     // 43 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOff>>endobj
-    xref->fetch( 43, 0, &obj );
+    obj = xref->fetch( 43, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOn, multi-element array:
     // 50 0 obj<</Type/OCMD/OCGs[21 0 R 28 0 R]/P/AnyOn>>endobj
-    xref->fetch( 50, 0, &obj );
+    obj = xref->fetch( 50, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOff, multi-element array:
     // 57 0 obj<</Type/OCMD/P/AnyOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 57, 0, &obj );
+    obj = xref->fetch( 57, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOn, multi-element array:
     // 64 0 obj<</Type/OCMD/P/AllOn/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 64, 0, &obj );
+    obj = xref->fetch( 64, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOff, multi-element array:
     // 71 0 obj<</Type/OCMD/P/AllOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 71, 0, &obj );
+    obj = xref->fetch( 71, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     delete doc;
     delete globalParams;
diff --git a/test/pdf-fullrewrite.cc b/test/pdf-fullrewrite.cc
index 8108372..1f8fcc4 100644
--- a/test/pdf-fullrewrite.cc
+++ b/test/pdf-fullrewrite.cc
@@ -124,14 +124,11 @@
    * contain the same number of entries, we don't need to check that every key
    * in dictB is also contained in dictA */
   for (int i = 0; i < length; ++i) {
-    Object valA, valB;
     const char *key = dictA->getKey(i);
-    dictA->getValNF(i, &valA);
-    dictB->lookupNF(key, &valB);
+    Object valA = dictA->getValNF(i);
+    Object valB = dictB->lookupNF(key);
     if (!compareObjects(&valA, &valB))
       return gFalse;
-    valA.free();
-    valB.free();
   }
 
   return gTrue;
@@ -200,14 +197,11 @@
           return gFalse;
         } else {
           for (int i = 0; i < length; ++i) {
-            Object elemA, elemB;
-            arrayA->getNF(i, &elemA);
-            arrayB->getNF(i, &elemB);
+            Object elemA = arrayA->getNF(i);
+            Object elemB = arrayB->getNF(i);
             if (!compareObjects(&elemA, &elemB)) {
               return gFalse;
             }
-            elemA.free();
-            elemB.free();
           }
           return gTrue;
         }
@@ -348,15 +342,12 @@
     }
 
     // Compare contents
-    Object origObj, newObj;
-    origXRef->fetch(i, origGenNum, &origObj);
-    newXRef->fetch(i, newGenNum, &newObj);
+    Object origObj = origXRef->fetch(i, origGenNum);
+    Object newObj = newXRef->fetch(i, newGenNum);
     if (!compareObjects(&origObj, &newObj)) {
       fprintf(stderr, "XRef entry %u: contents differ\n", i);
       result = gFalse;
     }
-    origObj.free();
-    newObj.free();
   }
 
   return result;
diff --git a/utils/pdfinfo.cc b/utils/pdfinfo.cc
index 9cfdc0f..738a506 100644
--- a/utils/pdfinfo.cc
+++ b/utils/pdfinfo.cc
@@ -15,7 +15,7 @@
 // under GPL version 2 or later
 //
 // Copyright (C) 2006 Dom Lachowicz <cinamod@hotmail.com>
-// Copyright (C) 2007-2010, 2012, 2016 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2007-2010, 2012, 2016, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
 // Copyright (C) 2011 Vittal Aithal <vittal.aithal@cognidox.com>
 // Copyright (C) 2012, 2013, 2016 Adrian Johnson <ajohnson@redneon.com>
@@ -120,13 +120,13 @@
 
 static void printInfoString(Dict *infoDict, const char *key, const char *text,
 			    UnicodeMap *uMap) {
-  Object obj;
   GooString *s1;
   Unicode *u;
   char buf[8];
   int i, n, len;
 
-  if (infoDict->lookup(key, &obj)->isString()) {
+  Object obj = infoDict->lookup(key);
+  if (obj.isString()) {
     fputs(text, stdout);
     s1 = obj.getString();
     len = TextStringToUCS4(s1, &u);
@@ -137,11 +137,9 @@
     gfree(u);
     fputc('\n', stdout);
   }
-  obj.free();
 }
 
 static void printInfoDate(Dict *infoDict, const char *key, const char *text) {
-  Object obj;
   char *s;
   int year, mon, day, hour, min, sec, tz_hour, tz_minute;
   char tz;
@@ -149,7 +147,8 @@
   time_t time;
   char buf[256];
 
-  if (infoDict->lookup(key, &obj)->isString()) {
+  Object obj = infoDict->lookup(key);
+  if (obj.isString()) {
     fputs(text, stdout);
     s = obj.getString()->getCString();
     // TODO do something with the timezone info
@@ -181,17 +180,16 @@
     }
     fputc('\n', stdout);
   }
-  obj.free();
 }
 
 void printISODate(Dict *infoDict, const char *key, const char *text)
 {
-  Object obj;
   char *s;
   int year, mon, day, hour, min, sec, tz_hour, tz_minute;
   char tz;
 
-  if (infoDict->lookup(key, &obj)->isString()) {
+  Object obj = infoDict->lookup(key);
+  if (obj.isString()) {
     fputs(text, stdout);
     s = obj.getString()->getCString();
     if ( parseDateString( s, &year, &mon, &day, &hour, &min, &sec, &tz, &tz_hour, &tz_minute ) ) {
@@ -208,7 +206,6 @@
     }
     fputc('\n', stdout);
   }
-  obj.free();
 }
 
 static void printBox(const char *text, PDFRectangle *box) {
@@ -291,14 +288,13 @@
 
 void printInfo(PDFDoc *doc, UnicodeMap *uMap, long long filesize, GBool multiPage) {
   Page *page;
-  Object info;
   char buf[256];
   double w, h, wISO, hISO;
   int pg, i;
   int r;
 
   // print doc info
-  doc->getDocInfo(&info);
+  Object info = doc->getDocInfo();
   if (info.isDict()) {
     printInfoString(info.getDict(), "Title",        "Title:          ", uMap);
     printInfoString(info.getDict(), "Subject",      "Subject:        ", uMap);
@@ -319,7 +315,6 @@
       printInfoDate(info.getDict(),   "ModDate",      "ModDate:        ");
     }
   }
-  info.free();
 
   // print tagging info
    printf("Tagged:         %s\n",
diff --git a/utils/pdftohtml.cc b/utils/pdftohtml.cc
index 50d8990..8e59b8b 100644
--- a/utils/pdftohtml.cc
+++ b/utils/pdftohtml.cc
@@ -13,7 +13,7 @@
 // All changes made under the Poppler project to this file are licensed
 // under GPL version 2 or later
 //
-// Copyright (C) 2007-2008, 2010, 2012, 2015, 2016 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2007-2008, 2010, 2012, 2015-2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
 // Copyright (C) 2010 Mike Slegeir <tehpola@yahoo.com>
 // Copyright (C) 2010, 2013 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
@@ -333,7 +333,7 @@
     goto error;
   }
 
-  doc->getDocInfo(&info);
+  info = doc->getDocInfo();
   if (info.isDict()) {
     docTitle = getInfoString(info.getDict(), "Title");
     author = getInfoString(info.getDict(), "Author");
@@ -343,7 +343,6 @@
     if( !date )
 	date = getInfoDate(info.getDict(), "CreationDate");
   }
-  info.free();
   if( !docTitle ) docTitle = new GooString(htmlFileName);
 
   if (!singleHtml)
@@ -464,7 +463,8 @@
   // Is rawString UCS2 (as opposed to pdfDocEncoding)
   GBool isUnicode;
 
-  if (infoDict->lookup(key, &obj)->isString()) {
+  obj = infoDict->lookup(key);
+  if (obj.isString()) {
     rawString = obj.getString();
 
     // Convert rawString to unicode
@@ -491,7 +491,6 @@
     delete[] unicodeString;
   }
 
-  obj.free();
   return encodedString;
 }
 
@@ -504,7 +503,8 @@
   GooString *result = NULL;
   char buf[256];
 
-  if (infoDict->lookup(key, &obj)->isString()) {
+  obj = infoDict->lookup(key);
+  if (obj.isString()) {
     s = obj.getString()->getCString();
     // TODO do something with the timezone info
     if ( parseDateString( s, &year, &mon, &day, &hour, &min, &sec, &tz, &tz_hour, &tz_minute ) ) {
@@ -527,7 +527,6 @@
       result = new GooString(s);
     }
   }
-  obj.free();
   return result;
 }
 
diff --git a/utils/pdftotext.cc b/utils/pdftotext.cc
index d931a96..141de72 100644
--- a/utils/pdftotext.cc
+++ b/utils/pdftotext.cc
@@ -16,7 +16,7 @@
 // under GPL version 2 or later
 //
 // Copyright (C) 2006 Dominic Lachowicz <cinamod@hotmail.com>
-// Copyright (C) 2007-2008, 2010, 2011 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2007-2008, 2010, 2011, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2009 Jan Jockusch <jan@jockusch.de>
 // Copyright (C) 2010, 2013 Hib Eris <hib@hiberis.nl>
 // Copyright (C) 2010 Kenneth Berland <ken@hero.com>
@@ -323,15 +323,14 @@
     fputs("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">", f);
     fputs("<html xmlns=\"http://www.w3.org/1999/xhtml\">\n", f);
     fputs("<head>\n", f);
-    doc->getDocInfo(&info);
+    info = doc->getDocInfo();
     if (info.isDict()) {
-      Object obj;
-      if (info.getDict()->lookup("Title", &obj)->isString()) {
+      Object obj = info.getDict()->lookup("Title");
+      if (obj.isString()) {
         printInfoString(f, info.getDict(), "Title", "<title>", "</title>\n", uMap);
       } else {
         fputs("<title></title>\n", f);
       }
-      obj.free();
       printInfoString(f, info.getDict(), "Subject",
 		      "<meta name=\"Subject\" content=\"", "\"/>\n", uMap);
       printInfoString(f, info.getDict(), "Keywords",
@@ -347,7 +346,6 @@
       printInfoDate(f, info.getDict(), "LastModifiedDate",
 		    "<meta name=\"ModDate\" content=\"\"/>\n");
     }
-    info.free();
     fputs("</head>\n", f);
     fputs("<body>\n", f);
     if (!bbox) {
@@ -438,14 +436,14 @@
 
 static void printInfoString(FILE *f, Dict *infoDict, const char *key,
 			    const char *text1, const char *text2, UnicodeMap *uMap) {
-  Object obj;
   GooString *s1;
   GBool isUnicode;
   Unicode u;
   char buf[9];
   int i, n;
 
-  if (infoDict->lookup(key, &obj)->isString()) {
+  Object obj = infoDict->lookup(key);
+  if (obj.isString()) {
     fputs(text1, f);
     s1 = obj.getString();
     if ((s1->getChar(0) & 0xff) == 0xfe &&
@@ -472,21 +470,17 @@
     }
     fputs(text2, f);
   }
-  obj.free();
 }
 
 static void printInfoDate(FILE *f, Dict *infoDict, const char *key, const char *fmt) {
-  Object obj;
-  char *s;
-
-  if (infoDict->lookup(key, &obj)->isString()) {
-    s = obj.getString()->getCString();
+  Object obj = infoDict->lookup(key);
+  if (obj.isString()) {
+    char *s = obj.getString()->getCString();
     if (s[0] == 'D' && s[1] == ':') {
       s += 2;
     }
     fprintf(f, fmt, s);
   }
-  obj.free();
 }
 
 void printLine(FILE *f, TextLine *line) {
diff --git a/utils/pdfunite.cc b/utils/pdfunite.cc
index c32e201..c223c80 100644
--- a/utils/pdfunite.cc
+++ b/utils/pdfunite.cc
@@ -39,149 +39,86 @@
 };
 
 void doMergeNameTree(PDFDoc *doc, XRef *srcXRef, XRef *countRef, int oldRefNum, int newRefNum, Dict *srcNameTree, Dict *mergeNameTree, int numOffset) {
-  Object mergeNameArray;
-  Object srcNameArray;
-  mergeNameTree->lookup("Names", &mergeNameArray);
-  srcNameTree->lookup("Names", &srcNameArray);
+  Object mergeNameArray = mergeNameTree->lookup("Names");
+  Object srcNameArray = srcNameTree->lookup("Names");
   if (mergeNameArray.isArray() && srcNameArray.isArray()) {
-    Object *newNameArray = new Object();
-    newNameArray->initArray(srcXRef);
+    Array *newNameArray = new Array(srcXRef);
     int j = 0;
     for (int i = 0; i < srcNameArray.arrayGetLength() - 1; i += 2) {
-      Object key;
-      Object value;
-      srcNameArray.arrayGetNF(i, &key);
-      srcNameArray.arrayGetNF(i + 1, &value);
+      Object key = srcNameArray.arrayGetNF(i);
+      Object value = srcNameArray.arrayGetNF(i + 1);
       if (key.isString() && value.isRef()) {
         while (j < mergeNameArray.arrayGetLength() - 1) {
-          Object mkey;
-          Object mvalue;
-          mergeNameArray.arrayGetNF(j, &mkey);
-          mergeNameArray.arrayGetNF(j + 1, &mvalue);
+          Object mkey = mergeNameArray.arrayGetNF(j);
+          Object mvalue = mergeNameArray.arrayGetNF(j + 1);
           if (mkey.isString() && mvalue.isRef()) {
             if (mkey.getString()->cmp(key.getString()) < 0) {
-              Object *newKey = new Object();
-	      newKey->initString(new GooString(mkey.getString()->getCString()));
-              newNameArray->arrayAdd(newKey);
-              Object *newValue = new Object();
-              newValue->initRef(mvalue.getRef().num + numOffset, mvalue.getRef().gen);
-              newNameArray->arrayAdd(newValue);
-              delete newKey;
-              delete newValue;
+              newNameArray->add(Object(new GooString(mkey.getString()->getCString())));
+              newNameArray->add(Object(mvalue.getRef().num + numOffset, mvalue.getRef().gen));
               j += 2;
             } else if (mkey.getString()->cmp(key.getString()) == 0) {
               j += 2;
             } else {
-              mkey.free();
-              mvalue.free();
               break;
             }
           } else {
             j += 2;
           }
-          mkey.free();
-          mvalue.free();
         }
-        Object *newKey = new Object();
-        newKey->initString(new GooString(key.getString()->getCString()));
-        newNameArray->arrayAdd(newKey);
-        Object *newValue = new Object();
-        newValue->initRef(value.getRef().num, value.getRef().gen);
-        newNameArray->arrayAdd(newValue);
-        delete newKey;
-        delete newValue;
+        newNameArray->add(Object(new GooString(key.getString()->getCString())));
+        newNameArray->add(Object(value.getRef().num, value.getRef().gen));
       }
-      key.free();
-      value.free();
     }
     while (j < mergeNameArray.arrayGetLength() - 1) {
-      Object mkey;
-      Object mvalue;
-      mergeNameArray.arrayGetNF(j, &mkey);
-      mergeNameArray.arrayGetNF(j + 1, &mvalue);
+      Object mkey = mergeNameArray.arrayGetNF(j);
+      Object mvalue = mergeNameArray.arrayGetNF(j + 1);
       if (mkey.isString() && mvalue.isRef()) {
-        Object *newKey = new Object();
-        newKey->initString(new GooString(mkey.getString()->getCString()));
-        newNameArray->arrayAdd(newKey);
-        Object *newValue = new Object();
-        newValue->initRef(mvalue.getRef().num + numOffset, mvalue.getRef().gen);
-        newNameArray->arrayAdd(newValue);
-        delete newKey;
-        delete newValue;
+        newNameArray->add(Object(new GooString(mkey.getString()->getCString())));
+        newNameArray->add(Object(mvalue.getRef().num + numOffset, mvalue.getRef().gen));
       }
       j += 2;
-      mkey.free();
-      mvalue.free();
     }
-    srcNameTree->set("Names", newNameArray);
+    srcNameTree->set("Names", Object(newNameArray));
     doc->markPageObjects(mergeNameTree, srcXRef, countRef, numOffset, oldRefNum, newRefNum);
-    delete newNameArray;
   } else if (srcNameArray.isNull() && mergeNameArray.isArray()) {
-    Object *newNameArray = new Object();
-    newNameArray->initArray(srcXRef);
+    Array *newNameArray = new Array(srcXRef);
     for (int i = 0; i < mergeNameArray.arrayGetLength() - 1; i += 2) {
-      Object key;
-      Object value;
-      mergeNameArray.arrayGetNF(i, &key);
-      mergeNameArray.arrayGetNF(i + 1, &value);
+      Object key = mergeNameArray.arrayGetNF(i);
+      Object value = mergeNameArray.arrayGetNF(i + 1);
       if (key.isString() && value.isRef()) {
-        Object *newKey = new Object();
-	newKey->initString(new GooString(key.getString()->getCString()));
-        newNameArray->arrayAdd(newKey);
-        Object *newValue = new Object();
-        newValue->initRef(value.getRef().num + numOffset, value.getRef().gen);
-        newNameArray->arrayAdd(newValue);
-        delete newKey;
-        delete newValue;
+        newNameArray->add(Object(new GooString(key.getString()->getCString())));
+        newNameArray->add(Object(value.getRef().num + numOffset, value.getRef().gen));
       }
-      key.free();
-      value.free();
     }
-    srcNameTree->add(copyString("Names"), newNameArray);
+    srcNameTree->add(copyString("Names"), Object(newNameArray));
     doc->markPageObjects(mergeNameTree, srcXRef, countRef, numOffset, oldRefNum, newRefNum);
   }
-  mergeNameArray.free();
-  srcNameArray.free();
 }
 
 void doMergeNameDict(PDFDoc *doc, XRef *srcXRef, XRef *countRef, int oldRefNum, int newRefNum, Dict *srcNameDict, Dict *mergeNameDict, int numOffset) {
   for (int i = 0; i < mergeNameDict->getLength(); i++) {
     const char *key = mergeNameDict->getKey(i);
-    Object mergeNameTree;
-    Object srcNameTree;
-    mergeNameDict->lookup(key, &mergeNameTree);
-    srcNameDict->lookup(key, &srcNameTree);
+    Object mergeNameTree = mergeNameDict->lookup(key);
+    Object srcNameTree = srcNameDict->lookup(key);
     if (srcNameTree.isDict() && mergeNameTree.isDict()) {
       doMergeNameTree(doc, srcXRef, countRef, oldRefNum, newRefNum, srcNameTree.getDict(), mergeNameTree.getDict(), numOffset);
     } else if (srcNameTree.isNull() && mergeNameTree.isDict()) {
-      Object *newNameTree = new Object();
-      newNameTree->initDict(srcXRef);
-      doMergeNameTree(doc, srcXRef, countRef, oldRefNum, newRefNum, newNameTree->getDict(), mergeNameTree.getDict(), numOffset);
-      srcNameDict->add(copyString(key), newNameTree);
+      Object newNameTree(new Dict(srcXRef));
+      doMergeNameTree(doc, srcXRef, countRef, oldRefNum, newRefNum, newNameTree.getDict(), mergeNameTree.getDict(), numOffset);
+      srcNameDict->add(copyString(key), std::move(newNameTree));
     }
-    srcNameTree.free();
-    mergeNameTree.free();
   }
 }
 
 void doMergeFormDict(Dict *srcFormDict, Dict *mergeFormDict, int numOffset) {
-  Object srcFields, mergeFields;
-
-  srcFormDict->lookup("Fields", &srcFields);
-  mergeFormDict->lookup("Fields", &mergeFields);
+  Object srcFields = srcFormDict->lookup("Fields");
+  Object mergeFields = mergeFormDict->lookup("Fields");
   if (srcFields.isArray() && mergeFields.isArray()) {
     for (int i = 0; i < mergeFields.arrayGetLength(); i++) {
-      Object value;
-      Object *newValue = new Object();
-      mergeFields.arrayGetNF(i, &value);
-      newValue->initRef(value.getRef().num + numOffset, value.getRef().gen);
-      srcFields.arrayAdd(newValue);
-      value.free();
-      delete newValue;
+      Object value = mergeFields.arrayGetNF(i);
+      srcFields.arrayAdd(Object(value.getRef().num + numOffset, value.getRef().gen));
     }
   }
-  srcFields.free();
-  mergeFields.free();
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -258,58 +195,50 @@
 
   // handle OutputIntents, AcroForm, OCProperties & Names
   Object intents;
+  Object names;
   Object afObj;
   Object ocObj;
-  Object names;
   if (docs.size() >= 1) {
-    Object catObj;
-    docs[0]->getXRef()->getCatalog(&catObj);
+    Object catObj = docs[0]->getXRef()->getCatalog();
     Dict *catDict = catObj.getDict();
-    catDict->lookup("OutputIntents", &intents);
-    catDict->lookupNF("AcroForm", &afObj);
+    intents = catDict->lookup("OutputIntents");
+    afObj = catDict->lookupNF("AcroForm");
     Ref *refPage = docs[0]->getCatalog()->getPageRef(1);
     if (!afObj.isNull() && refPage) {
       docs[0]->markAcroForm(&afObj, yRef, countRef, 0, refPage->num, refPage->num);
     }
-    catDict->lookupNF("OCProperties", &ocObj);
+    ocObj = catDict->lookupNF("OCProperties");
     if (!ocObj.isNull() && ocObj.isDict() && refPage) {
       docs[0]->markPageObjects(ocObj.getDict(), yRef, countRef, 0, refPage->num, refPage->num);
     }
-    catDict->lookup("Names", &names);
+    names = catDict->lookup("Names");
     if (!names.isNull() && names.isDict() && refPage) {
       docs[0]->markPageObjects(names.getDict(), yRef, countRef, 0, refPage->num, refPage->num);
     }
     if (intents.isArray() && intents.arrayGetLength() > 0) {
       for (i = 1; i < (int) docs.size(); i++) {
-        Object pagecatObj, pageintents;
-        docs[i]->getXRef()->getCatalog(&pagecatObj);
+        Object pagecatObj = docs[i]->getXRef()->getCatalog();
         Dict *pagecatDict = pagecatObj.getDict();
-        pagecatDict->lookup("OutputIntents", &pageintents);
+        Object pageintents = pagecatDict->lookup("OutputIntents");
         if (pageintents.isArray() && pageintents.arrayGetLength() > 0) {
           for (j = intents.arrayGetLength() - 1; j >= 0; j--) {
-            Object intent;
-            intents.arrayGet(j, &intent, 0);
+            Object intent = intents.arrayGet(j, 0);
             if (intent.isDict()) {
-              Object idf;
-              intent.dictLookup("OutputConditionIdentifier", &idf);
+              Object idf = intent.dictLookup("OutputConditionIdentifier");
               if (idf.isString()) {
                 GooString *gidf = idf.getString();
                 GBool removeIntent = gTrue;
                 for (int k = 0; k < pageintents.arrayGetLength(); k++) {
-                  Object pgintent;
-                  pageintents.arrayGet(k, &pgintent, 0);
+                  Object pgintent = pageintents.arrayGet(k, 0);
                   if (pgintent.isDict()) {
-                    Object pgidf;
-                    pgintent.dictLookup("OutputConditionIdentifier", &pgidf);
+                    Object pgidf = pgintent.dictLookup("OutputConditionIdentifier");
                     if (pgidf.isString()) {
                       GooString *gpgidf = pgidf.getString();
                       if (gpgidf->cmp(gidf) == 0) {
-                        pgidf.free();
                         removeIntent = gFalse;
                         break;
                       }
                     }
-                    pgidf.free();
                   }
                 }
                 if (removeIntent) {
@@ -321,34 +250,26 @@
                 intents.arrayRemove(j);
                 error(errSyntaxWarning, -1, "Invalid output intent dict, missing required OutputConditionIdentifier");
               }
-              idf.free();
             } else {
               intents.arrayRemove(j);
             }
-            intent.free();
           }
         } else {
           error(errSyntaxWarning, -1, "Output intents differs, remove them all");
-          intents.free();
           break;
         }
-        pagecatObj.free();
-        pageintents.free();
       }
     }
     if (intents.isArray() && intents.arrayGetLength() > 0) {
       for (j = intents.arrayGetLength() - 1; j >= 0; j--) {
-        Object intent;
-        intents.arrayGet(j, &intent, 0);
+        Object intent = intents.arrayGet(j, 0);
         if (intent.isDict()) {
           docs[0]->markPageObjects(intent.getDict(), yRef, countRef, numOffset, 0, 0);
         } else {
           intents.arrayRemove(j);
         }
-        intent.free();
       }
     }
-    catObj.free();
   }
 
   for (i = 0; i < (int) docs.size(); i++) {
@@ -364,48 +285,37 @@
 	    docs[i]->getCatalog()->getPage(j)->getRotate(),
 	    docs[i]->getCatalog()->getPage(j)->getMediaBox(), cropBox);
       Ref *refPage = docs[i]->getCatalog()->getPageRef(j);
-      Object page;
-      docs[i]->getXRef()->fetch(refPage->num, refPage->gen, &page);
+      Object page = docs[i]->getXRef()->fetch(refPage->num, refPage->gen);
       Dict *pageDict = page.getDict();
-      Dict *resDict = docs[i]->getCatalog()->getPage(j)->getResourceDict();
-      if (resDict) {
-        Object *newResource = new Object();
-        newResource->initDict(resDict);
-        pageDict->set("Resources", newResource);
-        delete newResource;
+      Object *resDict = docs[i]->getCatalog()->getPage(j)->getResourceDictObject();
+      if (resDict->isDict()) {
+        pageDict->set("Resources", resDict->copy());
       }
-      pages.push_back(page);
+      pages.push_back(std::move(page));
       offsets.push_back(numOffset);
       docs[i]->markPageObjects(pageDict, yRef, countRef, numOffset, refPage->num, refPage->num);
-      Object annotsObj;
-      pageDict->lookupNF("Annots", &annotsObj);
+      Object annotsObj = pageDict->lookupNF("Annots");
       if (!annotsObj.isNull()) {
         docs[i]->markAnnotations(&annotsObj, yRef, countRef, numOffset, refPage->num, refPage->num);
-        annotsObj.free();
       }
     }
-    Object pageCatObj, pageNames, pageForm;
-    docs[i]->getXRef()->getCatalog(&pageCatObj);
+    Object pageCatObj = docs[i]->getXRef()->getCatalog();
     Dict *pageCatDict = pageCatObj.getDict();
-    pageCatDict->lookup("Names", &pageNames);
+    Object pageNames = pageCatDict->lookup("Names");
     if (!pageNames.isNull() && pageNames.isDict()) {
       if (!names.isDict()) {
-        names.free();
-        names.initDict(yRef);
+        names = Object(new Dict(yRef));
       }
       doMergeNameDict(docs[i], yRef, countRef, 0, 0, names.getDict(), pageNames.getDict(), numOffset);
     }
-    pageCatDict->lookup("AcroForm", &pageForm);
+    Object pageForm = pageCatDict->lookup("AcroForm");
     if (i > 0 && !pageForm.isNull() && pageForm.isDict()) {
       if (afObj.isNull()) {
-        pageCatDict->lookupNF("AcroForm", &afObj);
+        afObj = pageCatDict->lookupNF("AcroForm");
       } else if (afObj.isDict()) {
         doMergeFormDict(afObj.getDict(), pageForm.getDict(), numOffset);
       }
     }
-    pageForm.free();
-    pageNames.free();
-    pageCatObj.free();
     objectsCount += docs[i]->writePageObjects(outStr, yRef, numOffset, gTrue);
     numOffset = yRef->getNumObjects() + 1;
   }
@@ -418,33 +328,27 @@
   if (intents.isArray() && intents.arrayGetLength() > 0) {
     outStr->printf(" /OutputIntents [");
     for (j = 0; j < intents.arrayGetLength(); j++) {
-      Object intent;
-      intents.arrayGet(j, &intent, 0);
+      Object intent = intents.arrayGet(j, 0);
       if (intent.isDict()) {
         PDFDoc::writeObject(&intent, outStr, yRef, 0, NULL, cryptRC4, 0, 0, 0);
       }
-      intent.free();
     }
     outStr->printf("]");
   }
-  intents.free();
   // insert AcroForm
   if (!afObj.isNull()) {
     outStr->printf(" /AcroForm ");
     PDFDoc::writeObject(&afObj, outStr, yRef, 0, NULL, cryptRC4, 0, 0, 0);
-    afObj.free();
   }
   // insert OCProperties
   if (!ocObj.isNull() && ocObj.isDict()) {
     outStr->printf(" /OCProperties ");
     PDFDoc::writeObject(&ocObj, outStr, yRef, 0, NULL, cryptRC4, 0, 0, 0);
-    ocObj.free();
   }
   // insert Names
   if (!names.isNull() && names.isDict()) {
     outStr->printf(" /Names ");
     PDFDoc::writeObject(&names, outStr, yRef, 0, NULL, cryptRC4, 0, 0, 0);
-    names.free();
   }
   outStr->printf(">>\nendobj\n");
   objectsCount++;
@@ -466,15 +370,13 @@
       if (j > 0)
 	outStr->printf(" ");
       const char *key = pageDict->getKey(j);
-      Object value;
-      pageDict->getValNF(j, &value);
+      Object value = pageDict->getValNF(j);
       if (strcmp(key, "Parent") == 0) {
         outStr->printf("/Parent %d 0 R", rootNum + 1);
       } else {
         outStr->printf("/%s ", key);
         PDFDoc::writeObject(&value, outStr, yRef, offsets[i], NULL, cryptRC4, 0, 0, 0);
       }
-      value.free();
     }
     outStr->printf(" >>\nendobj\n");
     objectsCount++;
@@ -483,18 +385,16 @@
   Ref ref;
   ref.num = rootNum;
   ref.gen = 0;
-  Dict *trailerDict = PDFDoc::createTrailerDict(objectsCount, gFalse, 0, &ref, yRef,
+  Object trailerDict = PDFDoc::createTrailerDict(objectsCount, gFalse, 0, &ref, yRef,
                                                 fileName, outStr->getPos());
-  PDFDoc::writeXRefTableTrailer(trailerDict, yRef, gTrue, // write all entries according to ISO 32000-1, 7.5.4 Cross-Reference Table: "For a file that has never been incrementally updated, the cross-reference section shall contain only one subsection, whose object numbering begins at 0."
+  PDFDoc::writeXRefTableTrailer(std::move(trailerDict), yRef, gTrue, // write all entries according to ISO 32000-1, 7.5.4 Cross-Reference Table: "For a file that has never been incrementally updated, the cross-reference section shall contain only one subsection, whose object numbering begins at 0."
                                 uxrefOffset, outStr, yRef);
-  delete trailerDict;
 
   outStr->close();
   delete outStr;
   fclose(f);
   delete yRef;
   delete countRef;
-  for (j = 0; j < (int) pages.size (); j++) pages[j].free();
   for (i = 0; i < (int) docs.size (); i++) delete docs[i];
   delete globalParams;
   return exitCode;