<commit_before>#include "mupdf/pdf.h"

static pdf_obj *
resolve_dest_rec(fz_context *ctx, pdf_document *doc, pdf_obj *dest, int depth)
{
	if (depth > 10) /* Arbitrary to avoid infinite recursion */
		return NULL;

	if (pdf_is_name(ctx, dest) || pdf_is_string(ctx, dest))
	{
		dest = pdf_lookup_dest(ctx, doc, dest);
		dest = resolve_dest_rec(ctx, doc, dest, depth+1);
		return dest;
	}

	else if (pdf_is_array(ctx, dest))
	{
		return dest;
	}

	else if (pdf_is_dict(ctx, dest))
	{
		dest = pdf_dict_get(ctx, dest, PDF_NAME_D);
		return resolve_dest_rec(ctx, doc, dest, depth+1);
	}

	else if (pdf_is_indirect(ctx, dest))
		return dest;

	return NULL;
}

static pdf_obj *
resolve_dest(fz_context *ctx, pdf_document *doc, pdf_obj *dest)
{
	return resolve_dest_rec(ctx, doc, dest, 0);
}

char *
pdf_parse_link_dest(fz_context *ctx, pdf_document *doc, pdf_obj *dest)
{
	pdf_obj *obj;
	char buf[256];
	char *ld;
	int page;
	int x, y;

	dest = resolve_dest(ctx, doc, dest);
	if (dest == NULL)
	{
		fz_warn(ctx, "undefined link destination");
		return NULL;
	}

	if (pdf_is_name(ctx, dest))
	{
		ld = pdf_to_name(ctx, dest);
		return fz_strdup(ctx, ld);
	}
	else if (pdf_is_string(ctx, dest))
	{
		ld = pdf_to_str_buf(ctx, dest);
		return fz_strdup(ctx, ld);
	}

	obj = pdf_array_get(ctx, dest, 0);
	if (pdf_is_int(ctx, obj))
		page = pdf_to_int(ctx, obj);
	else
	{
		fz_try(ctx)
			page = pdf_lookup_page_number(ctx, doc, obj);
		fz_catch(ctx)
			page = -1;
	}

	x = y = 0;
	obj = pdf_array_get(ctx, dest, 1);
	if (pdf_name_eq(ctx, obj, PDF_NAME_XYZ))
	{
		x = pdf_to_int(ctx, pdf_array_get(ctx, dest, 2));
		y = pdf_to_int(ctx, pdf_array_get(ctx, dest, 3));
	}
	else if (pdf_name_eq(ctx, obj, PDF_NAME_FitR))
	{
		x = pdf_to_int(ctx, pdf_array_get(ctx, dest, 2));
		y = pdf_to_int(ctx, pdf_array_get(ctx, dest, 5));
	}
	else if (pdf_name_eq(ctx, obj, PDF_NAME_FitH) || pdf_name_eq(ctx, obj, PDF_NAME_FitBH))
		y = pdf_to_int(ctx, pdf_array_get(ctx, dest, 2));
	else if (pdf_name_eq(ctx, obj, PDF_NAME_FitV) || pdf_name_eq(ctx, obj, PDF_NAME_FitBV))
		x = pdf_to_int(ctx, pdf_array_get(ctx, dest, 2));

	if (page >= 0)
	{
		if (x != 0 || y != 0)
			fz_snprintf(buf, sizeof buf, "#%d,%d,%d", page + 1, x, y);
		else
			fz_snprintf(buf, sizeof buf, "#%d", page + 1);
		return fz_strdup(ctx, buf);
	}

	return NULL;
}

char *
pdf_parse_file_spec(fz_context *ctx, pdf_document *doc, pdf_obj *file_spec, pdf_obj *dest)
{
	pdf_obj *filename=NULL;
	char *path = NULL;
	char *uri = NULL;
	char buf[256];
	size_t n;

	if (pdf_is_string(ctx, file_spec))
		filename = file_spec;

	if (pdf_is_dict(ctx, file_spec)) {
#if defined(_WIN32) || defined(_WIN64)
		filename = pdf_dict_get(ctx, file_spec, PDF_NAME_DOS);
#else
		filename = pdf_dict_get(ctx, file_spec, PDF_NAME_Unix);
#endif
		if (!filename)
			filename = pdf_dict_geta(ctx, file_spec, PDF_NAME_UF, PDF_NAME_F);
	}

	if (!pdf_is_string(ctx, filename))
	{
		fz_warn(ctx, "cannot parse file specification");
		return NULL;
	}

	path = pdf_to_utf8(ctx, filename);
#if defined(_WIN32) || defined(_WIN64)
	if (strcmp(pdf_to_name(ctx, pdf_dict_gets(ctx, file_spec, "FS")), "URL") != 0)
	{
		/* move the file name into the expected place and use the expected path separator */
		char *c;
		if (path[0] == '/' && (('A' <= path[1] && path[1] <= 'Z') || ('a' <= path[1] && path[1] <= 'z')) && path[2] == '/')
		{
			path[0] = path[1];
			path[1] = ':';
		}
		for (c = path; *c; c++)
		{
			if (*c == '/')
				*c = '\\';
		}
	}
#endif

	if (pdf_is_array(ctx, dest))
		fz_snprintf(buf, sizeof buf, "#page=%d", pdf_to_int(ctx, pdf_array_get(ctx, dest, 0)) + 1);
	else if (pdf_is_name(ctx, dest))
		fz_snprintf(buf, sizeof buf, "#%s", pdf_to_name(ctx, dest));
	else if (pdf_is_stream(ctx, dest))
		fz_snprintf(buf, sizeof buf, "#%s", pdf_to_str_buf(ctx, dest));
	else<commit_msg>Fix 697725: silly typo when parsing GoToR destination.<commit_after>#include "mupdf/pdf.h"

static pdf_obj *
resolve_dest_rec(fz_context *ctx, pdf_document *doc, pdf_obj *dest, int depth)
{
	if (depth > 10) /* Arbitrary to avoid infinite recursion */
		return NULL;

	if (pdf_is_name(ctx, dest) || pdf_is_string(ctx, dest))
	{
		dest = pdf_lookup_dest(ctx, doc, dest);
		dest = resolve_dest_rec(ctx, doc, dest, depth+1);
		return dest;
	}

	else if (pdf_is_array(ctx, dest))
	{
		return dest;
	}

	else if (pdf_is_dict(ctx, dest))
	{
		dest = pdf_dict_get(ctx, dest, PDF_NAME_D);
		return resolve_dest_rec(ctx, doc, dest, depth+1);
	}

	else if (pdf_is_indirect(ctx, dest))
		return dest;

	return NULL;
}

static pdf_obj *
resolve_dest(fz_context *ctx, pdf_document *doc, pdf_obj *dest)
{
	return resolve_dest_rec(ctx, doc, dest, 0);
}

char *
pdf_parse_link_dest(fz_context *ctx, pdf_document *doc, pdf_obj *dest)
{
	pdf_obj *obj;
	char buf[256];
	char *ld;
	int page;
	int x, y;

	dest = resolve_dest(ctx, doc, dest);
	if (dest == NULL)
	{
		fz_warn(ctx, "undefined link destination");
		return NULL;
	}

	if (pdf_is_name(ctx, dest))
	{
		ld = pdf_to_name(ctx, dest);
		return fz_strdup(ctx, ld);
	}
	else if (pdf_is_string(ctx, dest))
	{
		ld = pdf_to_str_buf(ctx, dest);
		return fz_strdup(ctx, ld);
	}

	obj = pdf_array_get(ctx, dest, 0);
	if (pdf_is_int(ctx, obj))
		page = pdf_to_int(ctx, obj);
	else
	{
		fz_try(ctx)
			page = pdf_lookup_page_number(ctx, doc, obj);
		fz_catch(ctx)
			page = -1;
	}

	x = y = 0;
	obj = pdf_array_get(ctx, dest, 1);
	if (pdf_name_eq(ctx, obj, PDF_NAME_XYZ))
	{
		x = pdf_to_int(ctx, pdf_array_get(ctx, dest, 2));
		y = pdf_to_int(ctx, pdf_array_get(ctx, dest, 3));
	}
	else if (pdf_name_eq(ctx, obj, PDF_NAME_FitR))
	{
		x = pdf_to_int(ctx, pdf_array_get(ctx, dest, 2));
		y = pdf_to_int(ctx, pdf_array_get(ctx, dest, 5));
	}
	else if (pdf_name_eq(ctx, obj, PDF_NAME_FitH) || pdf_name_eq(ctx, obj, PDF_NAME_FitBH))
		y = pdf_to_int(ctx, pdf_array_get(ctx, dest, 2));
	else if (pdf_name_eq(ctx, obj, PDF_NAME_FitV) || pdf_name_eq(ctx, obj, PDF_NAME_FitBV))
		x = pdf_to_int(ctx, pdf_array_get(ctx, dest, 2));

	if (page >= 0)
	{
		if (x != 0 || y != 0)
			fz_snprintf(buf, sizeof buf, "#%d,%d,%d", page + 1, x, y);
		else
			fz_snprintf(buf, sizeof buf, "#%d", page + 1);
		return fz_strdup(ctx, buf);
	}

	return NULL;
}

char *
pdf_parse_file_spec(fz_context *ctx, pdf_document *doc, pdf_obj *file_spec, pdf_obj *dest)
{
	pdf_obj *filename=NULL;
	char *path = NULL;
	char *uri = NULL;
	char buf[256];
	size_t n;

	if (pdf_is_string(ctx, file_spec))
		filename = file_spec;

	if (pdf_is_dict(ctx, file_spec)) {
#if defined(_WIN32) || defined(_WIN64)
		filename = pdf_dict_get(ctx, file_spec, PDF_NAME_DOS);
#else
		filename = pdf_dict_get(ctx, file_spec, PDF_NAME_Unix);
#endif
		if (!filename)
			filename = pdf_dict_geta(ctx, file_spec, PDF_NAME_UF, PDF_NAME_F);
	}

	if (!pdf_is_string(ctx, filename))
	{
		fz_warn(ctx, "cannot parse file specification");
		return NULL;
	}

	path = pdf_to_utf8(ctx, filename);
#if defined(_WIN32) || defined(_WIN64)
	if (strcmp(pdf_to_name(ctx, pdf_dict_gets(ctx, file_spec, "FS")), "URL") != 0)
	{
		/* move the file name into the expected place and use the expected path separator */
		char *c;
		if (path[0] == '/' && (('A' <= path[1] && path[1] <= 'Z') || ('a' <= path[1] && path[1] <= 'z')) && path[2] == '/')
		{
			path[0] = path[1];
			path[1] = ':';
		}
		for (c = path; *c; c++)
		{
			if (*c == '/')
				*c = '\\';
		}
	}
#endif

	if (pdf_is_array(ctx, dest))
		fz_snprintf(buf, sizeof buf, "#page=%d", pdf_to_int(ctx, pdf_array_get(ctx, dest, 0)) + 1);
	else if (pdf_is_name(ctx, dest))
		fz_snprintf(buf, sizeof buf, "#%s", pdf_to_name(ctx, dest));
	else if (pdf_is_string(ctx, dest))
		fz_snprintf(buf, sizeof buf, "#%s", pdf_to_str_buf(ctx, dest));
	else
{'fraction_non_alphanumeric': 0.16647066509865413, 'fraction_numerical': 0.013066771200836273, 'mean_word_length': 4.439943141435679, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4702234', 'n_tokens_mistral': 3569, 'n_tokens_neox': 3319, 'n_words': 770}