Example #1
0
static void sweepref(fz_obj *obj)
{
	int num = fz_to_num(obj);
	int gen = fz_to_gen(obj);

	if (num < 0 || num >= xref->len)
		return;
	if (uselist[num])
		return;

	uselist[num] = 1;

	/* Bake in /Length in stream objects */
	fz_try(ctx)
	{
		if (pdf_is_stream(xref, num, gen))
		{
			fz_obj *len = fz_dict_gets(obj, "Length");
			if (fz_is_indirect(len))
			{
				uselist[fz_to_num(len)] = 0;
				len = fz_resolve_indirect(len);
				fz_dict_puts(obj, "Length", len);
			}
		}
	}
	fz_catch(ctx)
	{
		/* Leave broken */
	}

	sweepobj(fz_resolve_indirect(obj));
}
Example #2
0
fz_error
pdf_load_shading(fz_shade **shadep, pdf_xref *xref, fz_obj *dict)
{
	fz_error error;
	fz_matrix mat;
	fz_obj *obj;
	fz_context *ctx = xref->ctx;

	if ((*shadep = pdf_find_item(ctx, xref->store, fz_drop_shade, dict)))
	{
		fz_keep_shade(*shadep);
		return fz_okay;
	}

	/* Type 2 pattern dictionary */
	if (fz_dict_gets(ctx, dict, "PatternType"))
	{
		obj = fz_dict_gets(ctx, dict, "Matrix");
		if (obj)
			mat = pdf_to_matrix(ctx, obj);
		else
			mat = fz_identity;

		obj = fz_dict_gets(ctx, dict, "ExtGState");
		if (obj)
		{
			if (fz_dict_gets(ctx, obj, "CA") || fz_dict_gets(ctx, obj, "ca"))
			{
				fz_warn(ctx, "shading with alpha not supported");
			}
		}

		obj = fz_dict_gets(ctx, dict, "Shading");
		if (!obj)
			return fz_error_make(ctx, "syntaxerror: missing shading dictionary");

		error = pdf_load_shading_dict(shadep, xref, obj, mat);
		if (error)
			return fz_error_note(ctx, error, "cannot load shading dictionary (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
	}

	/* Naked shading dictionary */
	else
	{
		error = pdf_load_shading_dict(shadep, xref, dict, fz_identity);
		if (error)
			return fz_error_note(ctx, error, "cannot load shading dictionary (%d %d R)", fz_to_num(dict), fz_to_gen(dict));
	}

	pdf_store_item(ctx, xref->store, fz_keep_shade, fz_drop_shade, dict, *shadep);

	return fz_okay;
}
fz_error
pdf_load_pattern(pdf_pattern **patp, pdf_xref *xref, fz_obj *dict)
{
	fz_error error;
	pdf_pattern *pat;
	fz_obj *obj;

	if ((*patp = pdf_find_item(xref->store, pdf_drop_pattern, dict)))
	{
		pdf_keep_pattern(*patp);
		return fz_okay;
	}

	pat = fz_malloc(sizeof(pdf_pattern));
	pat->refs = 1;
	pat->resources = NULL;
	pat->contents = NULL;

	/* Store pattern now, to avoid possible recursion if objects refer back to this one */
	pdf_store_item(xref->store, pdf_keep_pattern, pdf_drop_pattern, dict, pat);

	pat->ismask = fz_to_int(fz_dict_gets(dict, "PaintType")) == 2;
	pat->xstep = fz_to_real(fz_dict_gets(dict, "XStep"));
	pat->ystep = fz_to_real(fz_dict_gets(dict, "YStep"));

	obj = fz_dict_gets(dict, "BBox");
	pat->bbox = pdf_to_rect(obj);

	obj = fz_dict_gets(dict, "Matrix");
	if (obj)
		pat->matrix = pdf_to_matrix(obj);
	else
		pat->matrix = fz_identity;

	pat->resources = fz_dict_gets(dict, "Resources");
	if (pat->resources)
		fz_keep_obj(pat->resources);

	error = pdf_load_stream(&pat->contents, xref, fz_to_num(dict), fz_to_gen(dict));
	if (error)
	{
		pdf_remove_item(xref->store, pdf_drop_pattern, dict);
		pdf_drop_pattern(pat);
		return fz_rethrow(error, "cannot load pattern stream (%d %d R)", fz_to_num(dict), fz_to_gen(dict));
	}

	*patp = pat;
	return fz_okay;
}
Example #4
0
static fz_obj *
pdf_get_ap_stream(pdf_xref *xref, fz_obj *obj)
{
	fz_obj *ap = fz_dict_gets(xref->ctx, obj, "AP");
	if (!fz_is_dict(xref->ctx, ap))
		return NULL;

	ap = fz_dict_gets(xref->ctx, ap, "N");
	if (!pdf_is_stream(xref, fz_to_num(ap), fz_to_gen(ap)))
		ap = fz_dict_get(xref->ctx, ap, fz_dict_gets(xref->ctx, obj, "AS"));
	if (!pdf_is_stream(xref, fz_to_num(ap), fz_to_gen(ap)))
		return NULL;

	return ap;
}
Example #5
0
static fz_error
pdf_read_ocg(pdf_xref *xref)
{
	fz_obj *obj, *ocg;
	int len, i;
	pdf_ocg_descriptor *desc;

	obj = fz_dict_gets(fz_dict_gets(xref->trailer, "Root"), "OCProperties");
	if (obj == NULL)
		return fz_okay;
	ocg = fz_dict_gets(obj, "OCGs");
	if (ocg == NULL || !fz_is_array(ocg))
		/* Not ever supposed to happen, but live with it. */
		return fz_okay;
	len = fz_array_len(ocg);
	desc = fz_malloc(sizeof(*desc));
	desc->len = len;
	desc->ocgs = fz_calloc(len, sizeof(*desc->ocgs));
	desc->intent = NULL;

	for (i=0; i < len; i++)
	{
		fz_obj *o = fz_array_get(ocg, i);
		desc->ocgs[i].num = fz_to_num(o);
		desc->ocgs[i].gen = fz_to_gen(o);
		desc->ocgs[i].state = 0;
	}
	xref->ocg = desc;

	return pdf_ocg_set_config(xref, 0);
}
Example #6
0
static void renumberobj(fz_obj *obj)
{
	int i;
	fz_context *ctx = xref->ctx;

	if (fz_is_dict(obj))
	{
		int n = fz_dict_len(obj);
		for (i = 0; i < n; i++)
		{
			fz_obj *key = fz_dict_get_key(obj, i);
			fz_obj *val = fz_dict_get_val(obj, i);
			if (fz_is_indirect(val))
			{
				val = fz_new_indirect(ctx, renumbermap[fz_to_num(val)], 0, xref);
				fz_dict_put(obj, key, val);
				fz_drop_obj(val);
			}
			else
			{
				renumberobj(val);
			}
		}
	}

	else if (fz_is_array(obj))
	{
		int n = fz_array_len(obj);
		for (i = 0; i < n; i++)
		{
			fz_obj *val = fz_array_get(obj, i);
			if (fz_is_indirect(val))
			{
				val = fz_new_indirect(ctx, renumbermap[fz_to_num(val)], 0, xref);
				fz_array_put(obj, i, val);
				fz_drop_obj(val);
			}
			else
			{
				renumberobj(val);
			}
		}
	}
}
static fz_error
load_separation(fz_colorspace **csp, pdf_xref *xref, fz_obj *array)
{
	fz_error error;
	fz_colorspace *cs;
	struct separation *sep;
	fz_obj *nameobj = fz_array_get(array, 1);
	fz_obj *baseobj = fz_array_get(array, 2);
	fz_obj *tintobj = fz_array_get(array, 3);
	fz_colorspace *base;
	pdf_function *tint;
	int n;

	if (fz_is_array(nameobj))
		n = fz_array_len(nameobj);
	else
		n = 1;

	if (n > FZ_MAX_COLORS)
		return fz_throw("too many components in colorspace");

	error = pdf_load_colorspace(&base, xref, baseobj);
	if (error)
		return fz_rethrow(error, "cannot load base colorspace (%d %d R)", fz_to_num(baseobj), fz_to_gen(baseobj));

	error = pdf_load_function(&tint, xref, tintobj);
	if (error)
	{
		fz_drop_colorspace(base);
		return fz_rethrow(error, "cannot load tint function (%d %d R)", fz_to_num(tintobj), fz_to_gen(tintobj));
	}

	sep = fz_malloc(sizeof(struct separation));
	sep->base = base;
	sep->tint = tint;

	cs = fz_new_colorspace(n == 1 ? "Separation" : "DeviceN", n);
	cs->to_rgb = separation_to_rgb;
	cs->free_data = free_separation;
	cs->data = sep;

	*csp = cs;
	return fz_okay;
}
Example #8
0
static void renumberobjs(void)
{
	pdf_xref_entry *oldxref;
	int newlen;
	int num;

	/* Apply renumber map to indirect references in all objects in xref */
	renumberobj(xref->trailer);
	for (num = 0; num < xref->len; num++)
	{
		fz_obj *obj = xref->table[num].obj;

		if (fz_is_indirect(obj))
		{
			obj = fz_new_indirect(ctx, renumbermap[fz_to_num(obj)], 0, xref);
			pdf_update_object(xref, num, 0, obj);
			fz_drop_obj(obj);
		}
		else
		{
			renumberobj(obj);
		}
	}

	/* Create new table for the reordered, compacted xref */
	oldxref = xref->table;
	xref->table = fz_malloc_array(xref->ctx, xref->len, sizeof(pdf_xref_entry));
	xref->table[0] = oldxref[0];

	/* Move used objects into the new compacted xref */
	newlen = 0;
	for (num = 1; num < xref->len; num++)
	{
		if (uselist[num])
		{
			if (newlen < renumbermap[num])
				newlen = renumbermap[num];
			xref->table[renumbermap[num]] = oldxref[num];
		}
		else
		{
			if (oldxref[num].obj)
				fz_drop_obj(oldxref[num].obj);
		}
	}

	fz_free(xref->ctx, oldxref);

	/* Update the used objects count in compacted xref */
	xref->len = newlen + 1;

	/* Update list of used objects to fit with compacted xref */
	for (num = 1; num < xref->len; num++)
		uselist[num] = 1;
}
static fz_error
pdf_load_jpx_image(fz_pixmap **imgp, pdf_xref *xref, fz_obj *dict)
{
	fz_error error;
	fz_buffer *buf;
	fz_colorspace *colorspace;
	fz_pixmap *img;
	fz_obj *obj;

	colorspace = NULL;

	error = pdf_load_stream(&buf, xref, fz_to_num(dict), fz_to_gen(dict));
	if (error)
		return fz_rethrow(error, "cannot load jpx image data");

	obj = fz_dict_gets(dict, "ColorSpace");
	if (obj)
	{
		error = pdf_load_colorspace(&colorspace, xref, obj);
		if (error)
			fz_catch(error, "cannot load image colorspace");
	}

	error = fz_load_jpx_image(&img, buf->data, buf->len, colorspace);
	if (error)
	{
		if (colorspace)
			fz_drop_colorspace(colorspace);
		fz_drop_buffer(buf);
		return fz_rethrow(error, "cannot load jpx image");
	}

	if (colorspace)
		fz_drop_colorspace(colorspace);
	fz_drop_buffer(buf);

	obj = fz_dict_getsa(dict, "SMask", "Mask");
	if (fz_is_dict(obj))
	{
		error = pdf_load_image_imp(&img->mask, xref, NULL, obj, NULL, 1);
		if (error)
		{
			fz_drop_pixmap(img);
			return fz_rethrow(error, "cannot load image mask/softmask");
		}
	}

	*imgp = img;
	return fz_okay;
}
fz_error
pdf_load_colorspace(fz_colorspace **csp, pdf_xref *xref, fz_obj *obj)
{
	fz_error error;

	if ((*csp = pdf_find_item(xref->store, fz_drop_colorspace, obj)))
	{
		fz_keep_colorspace(*csp);
		return fz_okay;
	}

	error = pdf_load_colorspace_imp(csp, xref, obj);
	if (error)
		return fz_rethrow(error, "cannot load colorspace (%d %d R)", fz_to_num(obj), fz_to_gen(obj));

	pdf_store_item(xref->store, fz_keep_colorspace, fz_drop_colorspace, obj, *csp);

	return fz_okay;
}
Example #11
0
fz_error
pdf_load_image(fz_pixmap **pixp, pdf_xref *xref, fz_obj *dict)
{
	fz_error error;

	if ((*pixp = pdf_find_item(xref->store, fz_drop_pixmap, dict)))
	{
		fz_keep_pixmap(*pixp);
		return fz_okay;
	}

	error = pdf_load_image_imp(pixp, xref, NULL, dict, NULL, 0);
	if (error)
		return fz_rethrow(error, "cannot load image (%d 0 R)", fz_to_num(dict));


//	EBookDroid: Commented out for saving A LOTS of memory. Caching is not needed for embedded solutions
//	pdf_store_item(xref->store, fz_keep_pixmap, fz_drop_pixmap, dict, *pixp);

	return fz_okay;
}
Example #12
0
fz_obj *
pdf_resolve_indirect(fz_obj *ref)
{
	if (fz_is_indirect(ref))
	{
		pdf_xref *xref = fz_get_indirect_xref(ref);
		int num = fz_to_num(ref);
		int gen = fz_to_gen(ref);
		if (xref)
		{
			fz_error error = pdf_cache_object(xref, num, gen);
			if (error)
			{
				fz_catch(error, "cannot load object (%d %d R) into cache", num, gen);
				return ref;
			}
			if (xref->table[num].obj)
				return xref->table[num].obj;
		}
	}
	return ref;
}
static fz_error
pdf_load_colorspace_imp(fz_colorspace **csp, pdf_xref *xref, fz_obj *obj)
{
	if (fz_is_name(obj))
	{
		if (!strcmp(fz_to_name(obj), "Pattern"))
			*csp = fz_device_gray;
		else if (!strcmp(fz_to_name(obj), "G"))
			*csp = fz_device_gray;
		else if (!strcmp(fz_to_name(obj), "RGB"))
			*csp = fz_device_rgb;
		else if (!strcmp(fz_to_name(obj), "CMYK"))
			*csp = fz_device_cmyk;
		else if (!strcmp(fz_to_name(obj), "DeviceGray"))
			*csp = fz_device_gray;
		else if (!strcmp(fz_to_name(obj), "DeviceRGB"))
			*csp = fz_device_rgb;
		else if (!strcmp(fz_to_name(obj), "DeviceCMYK"))
			*csp = fz_device_cmyk;
		else
			return fz_throw("unknown colorspace: %s", fz_to_name(obj));
		return fz_okay;
	}

	else if (fz_is_array(obj))
	{
		fz_obj *name = fz_array_get(obj, 0);

		if (fz_is_name(name))
		{
			/* load base colorspace instead */
			if (!strcmp(fz_to_name(name), "Pattern"))
			{
				fz_error error;

				obj = fz_array_get(obj, 1);
				if (!obj)
				{
					*csp = fz_device_gray;
					return fz_okay;
				}

				error = pdf_load_colorspace(csp, xref, obj);
				if (error)
					return fz_rethrow(error, "cannot load pattern (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
			}

			else if (!strcmp(fz_to_name(name), "G"))
				*csp = fz_device_gray;
			else if (!strcmp(fz_to_name(name), "RGB"))
				*csp = fz_device_rgb;
			else if (!strcmp(fz_to_name(name), "CMYK"))
				*csp = fz_device_cmyk;
			else if (!strcmp(fz_to_name(name), "DeviceGray"))
				*csp = fz_device_gray;
			else if (!strcmp(fz_to_name(name), "DeviceRGB"))
				*csp = fz_device_rgb;
			else if (!strcmp(fz_to_name(name), "DeviceCMYK"))
				*csp = fz_device_cmyk;
			else if (!strcmp(fz_to_name(name), "CalGray"))
				*csp = fz_device_gray;
			else if (!strcmp(fz_to_name(name), "CalRGB"))
				*csp = fz_device_rgb;
			else if (!strcmp(fz_to_name(name), "CalCMYK"))
				*csp = fz_device_cmyk;
			else if (!strcmp(fz_to_name(name), "Lab"))
				*csp = fz_device_lab;

			else if (!strcmp(fz_to_name(name), "ICCBased"))
				return load_icc_based(csp, xref, fz_array_get(obj, 1));

			else if (!strcmp(fz_to_name(name), "Indexed"))
				return load_indexed(csp, xref, obj);
			else if (!strcmp(fz_to_name(name), "I"))
				return load_indexed(csp, xref, obj);

			else if (!strcmp(fz_to_name(name), "Separation"))
				return load_separation(csp, xref, obj);

			else if (!strcmp(fz_to_name(name), "DeviceN"))
				return load_separation(csp, xref, obj);

			else
				return fz_throw("syntaxerror: unknown colorspace %s", fz_to_name(name));

			return fz_okay;
		}
	}

	return fz_throw("syntaxerror: could not parse color space (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
}
static fz_error
load_indexed(fz_colorspace **csp, pdf_xref *xref, fz_obj *array)
{
	fz_error error;
	fz_colorspace *cs;
	struct indexed *idx;
	fz_obj *baseobj = fz_array_get(array, 1);
	fz_obj *highobj = fz_array_get(array, 2);
	fz_obj *lookup = fz_array_get(array, 3);
	fz_colorspace *base;
	int i, n;

	error = pdf_load_colorspace(&base, xref, baseobj);
	if (error)
		return fz_rethrow(error, "cannot load base colorspace (%d %d R)", fz_to_num(baseobj), fz_to_gen(baseobj));

	idx = fz_malloc(sizeof(struct indexed));
	idx->base = base;
	idx->high = fz_to_int(highobj);
	idx->high = CLAMP(idx->high, 0, 255);
	n = base->n * (idx->high + 1);
	idx->lookup = fz_malloc(n);
	memset(idx->lookup, 0, n);

	cs = fz_new_colorspace("Indexed", 1);
	cs->to_rgb = indexed_to_rgb;
	cs->free_data = free_indexed;
	cs->data = idx;

	if (fz_is_string(lookup) && fz_to_str_len(lookup) == n)
	{
		unsigned char *buf = (unsigned char *) fz_to_str_buf(lookup);
		for (i = 0; i < n; i++)
			idx->lookup[i] = buf[i];
	}
	else if (fz_is_indirect(lookup))
	{
		fz_stream *file;

		error = pdf_open_stream(&file, xref, fz_to_num(lookup), fz_to_gen(lookup));
		if (error)
		{
			fz_drop_colorspace(cs);
			return fz_rethrow(error, "cannot open colorspace lookup table (%d 0 R)", fz_to_num(lookup));
		}

		i = fz_read(file, idx->lookup, n);
		if (i < 0)
		{
			fz_drop_colorspace(cs);
			return fz_throw("cannot read colorspace lookup table (%d 0 R)", fz_to_num(lookup));
		}

		fz_close(file);
	}
	else
	{
		fz_drop_colorspace(cs);
		return fz_throw("cannot parse colorspace lookup table");
	}

	*csp = cs;
	return fz_okay;
}
Example #15
0
static fz_colorspace *
load_indexed(pdf_document *xref, fz_obj *array)
{
	struct indexed *idx = NULL;
	fz_context *ctx = xref->ctx;
	fz_obj *baseobj = fz_array_get(array, 1);
	fz_obj *highobj = fz_array_get(array, 2);
	fz_obj *lookup = fz_array_get(array, 3);
	fz_colorspace *base = NULL;
	fz_colorspace *cs = NULL;
	int i, n;

	fz_var(idx);
	fz_var(base);
	fz_var(cs);

	fz_try(ctx)
	{
		base = pdf_load_colorspace(xref, baseobj);
		/* "cannot load base colorspace (%d %d R)", fz_to_num(baseobj), fz_to_gen(baseobj) */

		idx = fz_malloc_struct(ctx, struct indexed);
		idx->lookup = NULL;
		idx->base = base;
		idx->high = fz_to_int(highobj);
		idx->high = CLAMP(idx->high, 0, 255);
		n = base->n * (idx->high + 1);
		idx->lookup = fz_malloc_array(ctx, 1, n);

		cs = fz_new_colorspace(ctx, "Indexed", 1);
		cs->to_rgb = indexed_to_rgb;
		cs->free_data = free_indexed;
		cs->data = idx;
		cs->size += sizeof(*idx) + n + (base ? base->size : 0);

		if (fz_is_string(lookup) && fz_to_str_len(lookup) == n)
		{
			unsigned char *buf = (unsigned char *) fz_to_str_buf(lookup);
			for (i = 0; i < n; i++)
				idx->lookup[i] = buf[i];
		}
		else if (fz_is_indirect(lookup))
		{
			fz_stream *file = NULL;

			fz_try(ctx)
			{
				file = pdf_open_stream(xref, fz_to_num(lookup), fz_to_gen(lookup));
			}
			fz_catch(ctx)
			{
				fz_throw(ctx, "cannot open colorspace lookup table (%d 0 R)", fz_to_num(lookup));
			}

			i = fz_read(file, idx->lookup, n);
			if (i < 0)
			{
				fz_close(file);
				fz_throw(ctx, "cannot read colorspace lookup table (%d 0 R)", fz_to_num(lookup));
			}

			fz_close(file);
		}
		else
		{
			fz_throw(ctx, "cannot parse colorspace lookup table");
		}
	}
fz_error
pdf_load_to_unicode(pdf_font_desc *font, pdf_xref *xref,
	char **strings, char *collection, fz_obj *cmapstm)
{
	fz_error error = fz_okay;
	pdf_cmap *cmap;
	int cid;
	int ucsbuf[8];
	int ucslen;
	int i;

	if (pdf_is_stream(xref, fz_to_num(cmapstm), fz_to_gen(cmapstm)))
	{
		error = pdf_load_embedded_cmap(&cmap, xref, cmapstm);
		if (error)
			return fz_rethrow(error, "cannot load embedded cmap (%d %d R)", fz_to_num(cmapstm), fz_to_gen(cmapstm));

		font->to_unicode = pdf_new_cmap();

		for (i = 0; i < (strings ? 256 : 65536); i++)
		{
			cid = pdf_lookup_cmap(font->encoding, i);
			if (cid >= 0)
			{
				ucslen = pdf_lookup_cmap_full(cmap, i, ucsbuf);
				if (ucslen == 1)
					pdf_map_range_to_range(font->to_unicode, cid, cid, ucsbuf[0]);
				if (ucslen > 1)
					pdf_map_one_to_many(font->to_unicode, cid, ucsbuf, ucslen);
			}
		}

		pdf_sort_cmap(font->to_unicode);

		pdf_drop_cmap(cmap);
	}

	else if (collection)
	{
		error = fz_okay;

		if (!strcmp(collection, "Adobe-CNS1"))
			error = pdf_load_system_cmap(&font->to_unicode, "Adobe-CNS1-UCS2");
		else if (!strcmp(collection, "Adobe-GB1"))
			error = pdf_load_system_cmap(&font->to_unicode, "Adobe-GB1-UCS2");
		else if (!strcmp(collection, "Adobe-Japan1"))
			error = pdf_load_system_cmap(&font->to_unicode, "Adobe-Japan1-UCS2");
		else if (!strcmp(collection, "Adobe-Korea1"))
			error = pdf_load_system_cmap(&font->to_unicode, "Adobe-Korea1-UCS2");

		if (error)
			return fz_rethrow(error, "cannot load ToUnicode system cmap %s-UCS2", collection);
	}

	if (strings)
	{
		/* TODO one-to-many mappings */

		font->cid_to_ucs_len = 256;
		font->cid_to_ucs = fz_calloc(256, sizeof(unsigned short));

		for (i = 0; i < 256; i++)
		{
			if (strings[i])
				font->cid_to_ucs[i] = pdf_lookup_agl(strings[i]);
			else
				font->cid_to_ucs[i] = '?';
		}
	}

	if (!font->to_unicode && !font->cid_to_ucs)
	{
		/* TODO: synthesize a ToUnicode if it's a freetype font with
		 * cmap and/or post tables or if it has glyph names. */
	}

	return fz_okay;
}
Example #17
0
static void retainpages(int argc, char **argv)
{
	fz_obj *oldroot, *root, *pages, *kids, *countobj, *parent, *olddests;

	/* Keep only pages/type and (reduced) dest entries to avoid
	 * references to unretained pages */
	oldroot = fz_dict_gets(xref->trailer, "Root");
	pages = fz_dict_gets(oldroot, "Pages");
	olddests = pdf_load_name_tree(xref, "Dests");

	root = fz_new_dict(ctx, 2);
	fz_dict_puts(root, "Type", fz_dict_gets(oldroot, "Type"));
	fz_dict_puts(root, "Pages", fz_dict_gets(oldroot, "Pages"));

	pdf_update_object(xref, fz_to_num(oldroot), fz_to_gen(oldroot), root);

	fz_drop_obj(root);

	/* Create a new kids array with only the pages we want to keep */
	parent = fz_new_indirect(ctx, fz_to_num(pages), fz_to_gen(pages), xref);
	kids = fz_new_array(ctx, 1);

	/* Retain pages specified */
	while (argc - fz_optind)
	{
		int page, spage, epage;
		char *spec, *dash;
		char *pagelist = argv[fz_optind];

		spec = fz_strsep(&pagelist, ",");
		while (spec)
		{
			dash = strchr(spec, '-');

			if (dash == spec)
				spage = epage = pdf_count_pages(xref);
			else
				spage = epage = atoi(spec);

			if (dash)
			{
				if (strlen(dash) > 1)
					epage = atoi(dash + 1);
				else
					epage = pdf_count_pages(xref);
			}

			if (spage > epage)
				page = spage, spage = epage, epage = page;

			if (spage < 1)
				spage = 1;
			if (epage > pdf_count_pages(xref))
				epage = pdf_count_pages(xref);

			for (page = spage; page <= epage; page++)
			{
				fz_obj *pageobj = xref->page_objs[page-1];
				fz_obj *pageref = xref->page_refs[page-1];

				fz_dict_puts(pageobj, "Parent", parent);

				/* Store page object in new kids array */
				fz_array_push(kids, pageref);
			}

			spec = fz_strsep(&pagelist, ",");
		}

		fz_optind++;
	}

	fz_drop_obj(parent);

	/* Update page count and kids array */
	countobj = fz_new_int(ctx, fz_array_len(kids));
	fz_dict_puts(pages, "Count", countobj);
	fz_drop_obj(countobj);
	fz_dict_puts(pages, "Kids", kids);
	fz_drop_obj(kids);

	/* Also preserve the (partial) Dests name tree */
	if (olddests)
	{
		int i;
		fz_obj *names = fz_new_dict(ctx, 1);
		fz_obj *dests = fz_new_dict(ctx, 1);
		fz_obj *names_list = fz_new_array(ctx, 32);

		for (i = 0; i < fz_dict_len(olddests); i++)
		{
			fz_obj *key = fz_dict_get_key(olddests, i);
			fz_obj *val = fz_dict_get_val(olddests, i);
			fz_obj *key_str = fz_new_string(ctx, fz_to_name(key), strlen(fz_to_name(key)));
			fz_obj *dest = fz_dict_gets(val, "D");

			dest = fz_array_get(dest ? dest : val, 0);
			if (fz_array_contains(fz_dict_gets(pages, "Kids"), dest))
			{
				fz_array_push(names_list, key_str);
				fz_array_push(names_list, val);
			}
			fz_drop_obj(key_str);
		}

		root = fz_dict_gets(xref->trailer, "Root");
		fz_dict_puts(dests, "Names", names_list);
		fz_dict_puts(names, "Dests", dests);
		fz_dict_puts(root, "Names", names);

		fz_drop_obj(names);
		fz_drop_obj(dests);
		fz_drop_obj(names_list);
		fz_drop_obj(olddests);
	}
}
Example #18
0
static void savefont(fz_obj *dict, int num)
{
	fz_error error;
	char name[1024];
	char *subtype;
	fz_buffer *buf;
	fz_obj *stream = NULL;
	fz_obj *obj;
	char *ext = "";
	FILE *f;
	char *fontname = "font";
	int n;

	obj = fz_dict_gets(ctx, dict, "FontName");
	if (obj)
		fontname = fz_to_name(ctx, obj);

	obj = fz_dict_gets(ctx, dict, "FontFile");
	if (obj)
	{
		stream = obj;
		ext = "pfa";
	}

	obj = fz_dict_gets(ctx, dict, "FontFile2");
	if (obj)
	{
		stream = obj;
		ext = "ttf";
	}

	obj = fz_dict_gets(ctx, dict, "FontFile3");
	if (obj)
	{
		stream = obj;

		obj = fz_dict_gets(ctx, obj, "Subtype");
		if (obj && !fz_is_name(ctx, obj))
			die(fz_error_make(ctx, "Invalid font descriptor subtype"));

		subtype = fz_to_name(ctx, obj);
		if (!strcmp(subtype, "Type1C"))
			ext = "cff";
		else if (!strcmp(subtype, "CIDFontType0C"))
			ext = "cid";
		else
			die(fz_error_make(ctx, "Unhandled font type '%s'", subtype));
	}

	if (!stream)
	{
		fz_warn(ctx, "Unhandled font type");
		return;
	}

	buf = fz_new_buffer(ctx, 0);

	error = pdf_load_stream(&buf, xref, fz_to_num(stream), fz_to_gen(stream));
	if (error)
		die(error);

	sprintf(name, "%s-%04d.%s", fontname, num, ext);
	printf("extracting font %s\n", name);

	f = fopen(name, "wb");
	if (f == NULL)
		die(fz_error_make(ctx, "Error creating font file"));

	n = fwrite(buf->data, 1, buf->len, f);
	if (n < buf->len)
		die(fz_error_make(ctx, "Error writing font file"));

	if (fclose(f) < 0)
		die(fz_error_make(ctx, "Error closing font file"));

	fz_drop_buffer(ctx, buf);
}
Example #19
0
static fz_error
pdf_load_image_imp(fz_pixmap **imgp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cstm, int forcemask)
{
	fz_stream *stm;
	fz_pixmap *tile;
	fz_obj *obj, *res;
	fz_error error;

	int w, h, bpc, n;
	int imagemask;
	int interpolate;
	int indexed;
	fz_colorspace *colorspace;
	fz_pixmap *mask; /* explicit mask/softmask image */
	int usecolorkey;
	int colorkey[FZ_MAX_COLORS * 2];
	float decode[FZ_MAX_COLORS * 2];

	int stride;
	unsigned char *samples;
	int i, len;

	/* special case for JPEG2000 images */
	if (pdf_is_jpx_image(dict))
	{
		tile = NULL;
		error = pdf_load_jpx_image(&tile, xref, dict);
		if (error)
			return fz_rethrow(error, "cannot load jpx image");
		if (forcemask)
		{
			if (tile->n != 2)
			{
				fz_drop_pixmap(tile);
				return fz_throw("softmask must be grayscale");
			}
			mask = fz_alpha_from_gray(tile, 1);
			fz_drop_pixmap(tile);
			*imgp = mask;
			return fz_okay;
		}
		*imgp = tile;
		return fz_okay;
	}

	w = fz_to_int(fz_dict_getsa(dict, "Width", "W"));
	h = fz_to_int(fz_dict_getsa(dict, "Height", "H"));
	bpc = fz_to_int(fz_dict_getsa(dict, "BitsPerComponent", "BPC"));
	imagemask = fz_to_bool(fz_dict_getsa(dict, "ImageMask", "IM"));
	interpolate = fz_to_bool(fz_dict_getsa(dict, "Interpolate", "I"));

	indexed = 0;
	usecolorkey = 0;
	colorspace = NULL;
	mask = NULL;

	if (imagemask)
		bpc = 1;

	if (w == 0)
		return fz_throw("image width is zero");
	if (h == 0)
		return fz_throw("image height is zero");
	if (bpc == 0)
		return fz_throw("image depth is zero");
	if (w > (1 << 16))
		return fz_throw("image is too wide");
	if (h > (1 << 16))
		return fz_throw("image is too high");

	obj = fz_dict_getsa(dict, "ColorSpace", "CS");
	if (obj && !imagemask && !forcemask)
	{
		/* colorspace resource lookup is only done for inline images */
		if (fz_is_name(obj))
		{
			res = fz_dict_get(fz_dict_gets(rdb, "ColorSpace"), obj);
			if (res)
				obj = res;
		}

		error = pdf_load_colorspace(&colorspace, xref, obj);
		if (error)
			return fz_rethrow(error, "cannot load image colorspace");

		if (!strcmp(colorspace->name, "Indexed"))
			indexed = 1;

		n = colorspace->n;
	}
	else
	{
		n = 1;
	}

	obj = fz_dict_getsa(dict, "Decode", "D");
	if (obj)
	{
		for (i = 0; i < n * 2; i++)
			decode[i] = fz_to_real(fz_array_get(obj, i));
	}
	else
	{
		float maxval = indexed ? (1 << bpc) - 1 : 1;
		for (i = 0; i < n * 2; i++)
			decode[i] = i & 1 ? maxval : 0;
	}

	obj = fz_dict_getsa(dict, "SMask", "Mask");
	if (fz_is_dict(obj))
	{
		/* Not allowed for inline images */
		if (!cstm)
		{
			error = pdf_load_image_imp(&mask, xref, rdb, obj, NULL, 1);
			if (error)
			{
				if (colorspace)
					fz_drop_colorspace(colorspace);
				return fz_rethrow(error, "cannot load image mask/softmask");
			}
		}
	}
	else if (fz_is_array(obj))
	{
		usecolorkey = 1;
		for (i = 0; i < n * 2; i++)
			colorkey[i] = fz_to_int(fz_array_get(obj, i));
	}

	/* Allocate now, to fail early if we run out of memory */
	tile = fz_new_pixmap_with_limit(colorspace, w, h);
	if (!tile)
	{
		if (colorspace)
			fz_drop_colorspace(colorspace);
		if (mask)
			fz_drop_pixmap(mask);
		return fz_throw("out of memory");
	}

	if (colorspace)
		fz_drop_colorspace(colorspace);

	tile->mask = mask;
	tile->interpolate = interpolate;

	stride = (w * n * bpc + 7) / 8;

	if (cstm)
	{
		stm = pdf_open_inline_stream(cstm, xref, dict, stride * h);
	}
	else
	{
		error = pdf_open_stream(&stm, xref, fz_to_num(dict), fz_to_gen(dict));
		if (error)
		{
			fz_drop_pixmap(tile);
			return fz_rethrow(error, "cannot open image data stream (%d 0 R)", fz_to_num(dict));
		}
	}

	samples = fz_calloc(h, stride);

	len = fz_read(stm, samples, h * stride);
	if (len < 0)
	{
		fz_close(stm);
		fz_free(samples);
		fz_drop_pixmap(tile);
		return fz_rethrow(len, "cannot read image data");
	}

	/* Make sure we read the EOF marker (for inline images only) */
	if (cstm)
	{
		unsigned char tbuf[512];
		int tlen = fz_read(stm, tbuf, sizeof tbuf);
		if (tlen < 0)
			fz_catch(tlen, "ignoring error at end of image");
		if (tlen > 0)
			fz_warn("ignoring garbage at end of image");
	}

	fz_close(stm);

	/* Pad truncated images */
	if (len < stride * h)
	{
		fz_warn("padding truncated image (%d 0 R)", fz_to_num(dict));
		memset(samples + len, 0, stride * h - len);
	}

	/* Invert 1-bit image masks */
	if (imagemask)
	{
		/* 0=opaque and 1=transparent so we need to invert */
		unsigned char *p = samples;
		len = h * stride;
		for (i = 0; i < len; i++)
			p[i] = ~p[i];
	}

	fz_unpack_tile(tile, samples, n, bpc, stride, indexed);

	fz_free(samples);

	if (usecolorkey)
		pdf_mask_color_key(tile, n, colorkey);

	if (indexed)
	{
		fz_pixmap *conv;
		fz_decode_indexed_tile(tile, decode, (1 << bpc) - 1);
		conv = pdf_expand_indexed_pixmap(tile);
		fz_drop_pixmap(tile);
		tile = conv;
	}
	else
	{
		fz_decode_tile(tile, decode);
	}

	*imgp = tile;
	return fz_okay;
}
Example #20
0
static fz_error
pdf_load_shading_dict(fz_shade **shadep, pdf_xref *xref, fz_obj *dict, fz_matrix transform)
{
	fz_error error;
	fz_shade *shade;
	pdf_function *func[FZ_MAX_COLORS] = { NULL };
	fz_stream *stream = NULL;
	fz_obj *obj;
	int funcs;
	int type;
	int i;

	shade = fz_malloc(sizeof(fz_shade));
	shade->refs = 1;
	shade->type = FZ_MESH;
	shade->use_background = 0;
	shade->use_function = 0;
	shade->matrix = transform;
	shade->bbox = fz_infinite_rect;
	shade->extend[0] = 0;
	shade->extend[1] = 0;

	shade->mesh_len = 0;
	shade->mesh_cap = 0;
	shade->mesh = NULL;

	shade->colorspace = NULL;

	funcs = 0;

	obj = fz_dict_gets(dict, "ShadingType");
	type = fz_to_int(obj);

	obj = fz_dict_gets(dict, "ColorSpace");
	if (!obj)
	{
		fz_drop_shade(shade);
		return fz_throw("shading colorspace is missing");
	}
	error = pdf_load_colorspace(&shade->colorspace, xref, obj);
	if (error)
	{
		fz_drop_shade(shade);
		return fz_rethrow(error, "cannot load colorspace (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
	}

	obj = fz_dict_gets(dict, "Background");
	if (obj)
	{
		shade->use_background = 1;
		for (i = 0; i < shade->colorspace->n; i++)
			shade->background[i] = fz_to_real(fz_array_get(obj, i));
	}

	obj = fz_dict_gets(dict, "BBox");
	if (fz_is_array(obj))
	{
		shade->bbox = pdf_to_rect(obj);
	}

	obj = fz_dict_gets(dict, "Function");
	if (fz_is_dict(obj))
	{
		funcs = 1;

		error = pdf_load_function(&func[0], xref, obj);
		if (error)
		{
			error = fz_rethrow(error, "cannot load shading function (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
			goto cleanup;
		}
	}
	else if (fz_is_array(obj))
	{
		funcs = fz_array_len(obj);
		if (funcs != 1 && funcs != shade->colorspace->n)
		{
			error = fz_throw("incorrect number of shading functions");
			goto cleanup;
		}

		for (i = 0; i < funcs; i++)
		{
			error = pdf_load_function(&func[i], xref, fz_array_get(obj, i));
			if (error)
			{
				error = fz_rethrow(error, "cannot load shading function (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
				goto cleanup;
			}
		}
	}

	if (type >= 4 && type <= 7)
	{
		error = pdf_open_stream(&stream, xref, fz_to_num(dict), fz_to_gen(dict));
		if (error)
		{
			error = fz_rethrow(error, "cannot open shading stream (%d %d R)", fz_to_num(dict), fz_to_gen(dict));
			goto cleanup;
		}
	}

	switch (type)
	{
	case 1: pdf_load_function_based_shading(shade, xref, dict, func[0]); break;
	case 2: pdf_load_axial_shading(shade, xref, dict, funcs, func); break;
	case 3: pdf_load_radial_shading(shade, xref, dict, funcs, func); break;
	case 4: pdf_load_type4_shade(shade, xref, dict, funcs, func, stream); break;
	case 5: pdf_load_type5_shade(shade, xref, dict, funcs, func, stream); break;
	case 6: pdf_load_type6_shade(shade, xref, dict, funcs, func, stream); break;
	case 7: pdf_load_type7_shade(shade, xref, dict, funcs, func, stream); break;
	default:
		error = fz_throw("unknown shading type: %d", type);
		goto cleanup;
	}

	if (stream)
		fz_close(stream);
	for (i = 0; i < funcs; i++)
		if (func[i])
			pdf_drop_function(func[i]);

	*shadep = shade;
	return fz_okay;

cleanup:
	if (stream)
		fz_close(stream);
	for (i = 0; i < funcs; i++)
		if (func[i])
			pdf_drop_function(func[i]);
	fz_drop_shade(shade);

	return fz_rethrow(error, "cannot load shading type %d (%d %d R)", type, fz_to_num(dict), fz_to_gen(dict));
}
/*
 * Create a filter given a name and param dictionary.
 */
static fz_stream *
build_filter(fz_stream *chain, pdf_xref * xref, fz_obj * f, fz_obj * p, int num, int gen)
{
	fz_error error;
	char *s;

	s = fz_to_name(f);

	if (!strcmp(s, "ASCIIHexDecode") || !strcmp(s, "AHx"))
		return fz_open_ahxd(chain);

	else if (!strcmp(s, "ASCII85Decode") || !strcmp(s, "A85"))
		return fz_open_a85d(chain);

	else if (!strcmp(s, "CCITTFaxDecode") || !strcmp(s, "CCF"))
		return fz_open_faxd(chain, p);

	else if (!strcmp(s, "DCTDecode") || !strcmp(s, "DCT"))
		return fz_open_dctd(chain, p);

	else if (!strcmp(s, "RunLengthDecode") || !strcmp(s, "RL"))
		return fz_open_rld(chain);

	else if (!strcmp(s, "FlateDecode") || !strcmp(s, "Fl"))
	{
		fz_obj *obj = fz_dict_gets(p, "Predictor");
		if (fz_to_int(obj) > 1)
			return fz_open_predict(fz_open_flated(chain), p);
		return fz_open_flated(chain);
	}

	else if (!strcmp(s, "LZWDecode") || !strcmp(s, "LZW"))
	{
		fz_obj *obj = fz_dict_gets(p, "Predictor");
		if (fz_to_int(obj) > 1)
			return fz_open_predict(fz_open_lzwd(chain, p), p);
		return fz_open_lzwd(chain, p);
	}

	else if (!strcmp(s, "JBIG2Decode"))
	{
		fz_obj *obj = fz_dict_gets(p, "JBIG2Globals");
		if (obj)
		{
			fz_buffer *globals;
			error = pdf_load_stream(&globals, xref, fz_to_num(obj), fz_to_gen(obj));
			if (error)
				fz_catch(error, "cannot load jbig2 global segments");
			chain = fz_open_jbig2d(chain, globals);
			fz_drop_buffer(globals);
			return chain;
		}
		return fz_open_jbig2d(chain, NULL);
	}

	else if (!strcmp(s, "JPXDecode"))
		return chain; /* JPX decoding is special cased in the image loading code */

	else if (!strcmp(s, "Crypt"))
	{
		fz_obj *name;

		if (!xref->crypt)
		{
			fz_warn("crypt filter in unencrypted document");
			return chain;
		}

		name = fz_dict_gets(p, "Name");
		if (fz_is_name(name))
			return pdf_open_crypt_with_filter(chain, xref->crypt, fz_to_name(name), num, gen);

		return chain;
	}

	fz_warn("unknown filter name (%s)", s);
	return chain;
}
Example #22
0
void
pdf_load_annots(pdf_annot **annotp, pdf_xref *xref, fz_obj *annots)
{
	pdf_annot *annot, *head, *tail;
	fz_obj *obj, *ap, *as, *n, *rect;
	pdf_xobject *form;
	fz_error error;
	int i;
	fz_context *ctx = xref->ctx;

	head = tail = NULL;
	annot = NULL;

	for (i = 0; i < fz_array_len(ctx, annots); i++)
	{
		obj = fz_array_get(ctx, annots, i);

		/* cf. http://bugs.ghostscript.com/show_bug.cgi?id=692078 */
		if ((annot = pdf_update_tx_widget_annot(xref, obj)))
		{
			if (!head)
				head = tail = annot;
			else
			{
				tail->next = annot;
				tail = annot;
			}
			continue;
		}

		rect = fz_dict_gets(ctx, obj, "Rect");
		ap = fz_dict_gets(ctx, obj, "AP");
		as = fz_dict_gets(ctx, obj, "AS");
		if (fz_is_dict(ctx, ap))
		{
			n = fz_dict_gets(ctx, ap, "N"); /* normal state */

			/* lookup current state in sub-dictionary */
			if (!pdf_is_stream(xref, fz_to_num(n), fz_to_gen(n)))
				n = fz_dict_get(ctx, n, as);

			if (pdf_is_stream(xref, fz_to_num(n), fz_to_gen(n)))
			{
				error = pdf_load_xobject(&form, xref, n);
				if (error)
				{
					fz_error_handle(ctx, error, "ignoring broken annotation");
					continue;
				}

				annot = fz_malloc(ctx, sizeof(pdf_annot));
				annot->obj = fz_keep_obj(obj);
				annot->rect = pdf_to_rect(ctx, rect);
				annot->ap = form;
				annot->next = NULL;

				pdf_transform_annot(annot);

				if (annot)
				{
					if (!head)
						head = tail = annot;
					else
					{
						tail->next = annot;
						tail = annot;
					}
				}
			}
		}
		/* SumatraPDF: synthesize appearance streams for a few more annotations */
		else if ((annot = pdf_create_annot_with_appearance(xref, obj)))
		{
			if (!head)
				head = tail = annot;
			else
			{
				tail->next = annot;
				tail = annot;
			}
		}
	}

	*annotp = head;
}
/*
 * Load CMap stream in PDF file
 */
fz_error
pdf_load_embedded_cmap(pdf_cmap **cmapp, pdf_xref *xref, fz_obj *stmobj)
{
	fz_error error = fz_okay;
	fz_stream *file = NULL;
	pdf_cmap *cmap = NULL;
	pdf_cmap *usecmap;
	fz_obj *wmode;
	fz_obj *obj;

	if ((*cmapp = pdf_find_item(xref->store, pdf_drop_cmap, stmobj)))
	{
		pdf_keep_cmap(*cmapp);
		return fz_okay;
	}

	error = pdf_open_stream(&file, xref, fz_to_num(stmobj), fz_to_gen(stmobj));
	if (error)
	{
		error = fz_rethrow(error, "cannot open cmap stream (%d %d R)", fz_to_num(stmobj), fz_to_gen(stmobj));
		goto cleanup;
	}

	error = pdf_parse_cmap(&cmap, file);
	if (error)
	{
		error = fz_rethrow(error, "cannot parse cmap stream (%d %d R)", fz_to_num(stmobj), fz_to_gen(stmobj));
		goto cleanup;
	}

	fz_close(file);

	wmode = fz_dict_gets(stmobj, "WMode");
	if (fz_is_int(wmode))
		pdf_set_wmode(cmap, fz_to_int(wmode));

	obj = fz_dict_gets(stmobj, "UseCMap");
	if (fz_is_name(obj))
	{
		error = pdf_load_system_cmap(&usecmap, fz_to_name(obj));
		if (error)
		{
			error = fz_rethrow(error, "cannot load system usecmap '%s'", fz_to_name(obj));
			goto cleanup;
		}
		pdf_set_usecmap(cmap, usecmap);
		pdf_drop_cmap(usecmap);
	}
	else if (fz_is_indirect(obj))
	{
		error = pdf_load_embedded_cmap(&usecmap, xref, obj);
		if (error)
		{
			error = fz_rethrow(error, "cannot load embedded usecmap (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
			goto cleanup;
		}
		pdf_set_usecmap(cmap, usecmap);
		pdf_drop_cmap(usecmap);
	}

	pdf_store_item(xref->store, pdf_keep_cmap, pdf_drop_cmap, stmobj, cmap);

	*cmapp = cmap;
	return fz_okay;

cleanup:
	if (file)
		fz_close(file);
	if (cmap)
		pdf_drop_cmap(cmap);
	return error; /* already rethrown */
}
Example #24
0
fz_error
pdf_ocg_set_config(pdf_xref *xref, int config)
{
	int i, j, len, len2;
	pdf_ocg_descriptor *desc = xref->ocg;
	fz_obj *obj, *cobj;
	char *name;

	obj = fz_dict_gets(fz_dict_gets(xref->trailer, "Root"), "OCProperties");
	if (obj == NULL)
	{
		if (config == 0)
			return fz_okay;
		else
			return fz_throw("Unknown OCG config (None known!)");
	}
	if (config == 0)
	{
		cobj = fz_dict_gets(obj, "D");
		if (cobj == NULL)
			return fz_throw("No default OCG config");
	}
	else
	{
		cobj = fz_array_get(fz_dict_gets(obj, "Configs"), config);
		if (cobj == NULL)
			return fz_throw("Illegal OCG config");
	}

	if (desc->intent != NULL)
		fz_drop_obj(desc->intent);
	desc->intent = fz_dict_gets(cobj, "Intent");
	if (desc->intent != NULL)
		fz_keep_obj(desc->intent);

	len = desc->len;
	name = fz_to_name(fz_dict_gets(cobj, "BaseState"));
	if (strcmp(name, "Unchanged") == 0)
	{
		/* Do nothing */
	}
	else if (strcmp(name, "OFF") == 0)
	{
		for (i = 0; i < len; i++)
		{
			desc->ocgs[i].state = 0;
		}
	}
	else /* Default to ON */
	{
		for (i = 0; i < len; i++)
		{
			desc->ocgs[i].state = 1;
		}
	}

	obj = fz_dict_gets(cobj, "ON");
	len2 = fz_array_len(obj);
	for (i = 0; i < len2; i++)
	{
		fz_obj *o = fz_array_get(obj, i);
		int n = fz_to_num(o);
		int g = fz_to_gen(o);
		for (j=0; j < len; j++)
		{
			if (desc->ocgs[j].num == n && desc->ocgs[j].gen == g)
			{
				desc->ocgs[j].state = 1;
				break;
			}
		}
	}

	obj = fz_dict_gets(cobj, "OFF");
	len2 = fz_array_len(obj);
	for (i = 0; i < len2; i++)
	{
		fz_obj *o = fz_array_get(obj, i);
		int n = fz_to_num(o);
		int g = fz_to_gen(o);
		for (j=0; j < len; j++)
		{
			if (desc->ocgs[j].num == n && desc->ocgs[j].gen == g)
			{
				desc->ocgs[j].state = 0;
				break;
			}
		}
	}

	/* FIXME: Should make 'num configs' available in the descriptor. */
	/* FIXME: Should copy out 'Intent' here into the descriptor, and remove
	 * csi->intent in favour of that. */
	/* FIXME: Should copy 'AS' into the descriptor, and visibility
	 * decisions should respect it. */
	/* FIXME: Make 'Order' available via the descriptor (when we have an
	 * app that needs it) */
	/* FIXME: Make 'ListMode' available via the descriptor (when we have
	 * an app that needs it) */
	/* FIXME: Make 'RBGroups' available via the descriptor (when we have
	 * an app that needs it) */
	/* FIXME: Make 'Locked' available via the descriptor (when we have
	 * an app that needs it) */
	return fz_okay;
}