diff --git a/pdf.c b/pdf.c
index 6a74caf4c91c7989ed17f411da9840cd9435e1ca..dd6855686b3efc46c94b7d1113c6962714182231 100644
--- a/pdf.c
+++ b/pdf.c
@@ -97,8 +97,14 @@ validate_eq_uint(HParseResult *p, void *u)
  * auxiliary global data structure needed by the parser
  */
 struct Env {
+	const char *infile;
 	const char *input;
 	size_t sz;
+
+	const HParsedToken **xrefs;
+	size_t nxrefs;
+	const HParsedToken **objs;
+	size_t nobjs;
 };
 
 
@@ -459,6 +465,13 @@ act_ks_bytes(const HParseResult *p, void *env)
 	return H_MAKE_BYTES(bs->token + offset, bs->len);
 }
 
+const HParsedToken *
+resolve(struct Env *aux, const HParsedToken *v)
+{
+	// XXX look up in cross-reference table
+	return v;
+}
+
 /*
  * This continuation takes the stream dictionary (as first element of x) and
  * should return a parser that consumes exactly the bytes that make up the
@@ -475,10 +488,10 @@ kstream(HAllocator *mm__, const HParsedToken *x, void *env)
 
 	/* look for the Length entry */
 	v = dictentry(dict, "Length");
+	v = resolve(aux, v);		/* resolve indirect references */
 	if (v == NULL || v->token_type != TT_SINT || v->sint < 0)
 		goto fail;
 	sz = (size_t)v->sint;
-		// XXX support indirect objects for the Length value!
 
 	//fprintf(stderr, "parsing stream object, length %zu.\n", sz);	// XXX debug
 
@@ -1061,14 +1074,38 @@ end:
 	return xrefs;
 }
 
+/* allocate space for the cross-reference table */
+void alloc_xreftable(struct Env *aux)
+{
+	const HParsedToken *v;
+	size_t n;
+
+	if (aux->nxrefs == 0)
+		return;
+
+	v = dictentry(H_INDEX_SEQ(aux->xrefs[0], 1), "Size");
+	if (v == NULL || v->token_type != TT_SINT || v->sint < 0) {
+		fprintf(stderr, "%s: invalid /Size in xref section\n",
+		    aux->infile);
+		return;
+	}
+	n = v->sint;
+
+	if (n > SIZE_MAX / sizeof(HParsedToken *))
+		errx(1, "malloc: size would overflow");
+	aux->objs = malloc(n * sizeof(HParsedToken *));
+	if (aux->objs == NULL)
+		err(1, "malloc");
+	aux->nobjs = n;
+}
+
 int
 main(int argc, char *argv[])
 {
 	struct Env aux;
 	HParseResult *res = NULL;
-	const HParsedToken **xrefs;
 	const uint8_t *input;
-	size_t sz, nxrefs;
+	size_t sz;
 	int fd;
 
 	/* command line handling */
@@ -1090,16 +1127,17 @@ main(int argc, char *argv[])
 		err(1, "mmap");
 
 	/* build parsers */
-	aux = (struct Env){input, sz};
+	aux = (struct Env){infile, input, sz};
 	init_parser(&aux);
 
 	/* parse all cross-reference sections and trailer dictionaries */
-	xrefs = parse_xrefs(input, sz, &nxrefs);
+	aux.xrefs = parse_xrefs(input, sz, &aux.nxrefs);
 	// XXX debug
-	//fprintf(stderr, "%s: %zu xref sections parsed\n", infile, nxrefs);
-	//for (size_t i = 0; i < nxrefs; i++)
-	//	h_pprintln(stderr, xrefs[i]);
-	(void)xrefs;	// shut up, gcc
+	//fprintf(stderr, "%s: %zu xref sections parsed\n", infile, aux.nxrefs);
+	//for (size_t i = 0; i < aux.nxrefs; i++)
+	//	h_pprintln(stderr, aux.xrefs[i]);
+
+	alloc_xreftable(&aux);
 
 	/* run the main parser */
 	res = h_parse(p_pdf, input, sz);