diff mupdf-source/source/xps/xps-zip.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mupdf-source/source/xps/xps-zip.c	Mon Sep 15 11:43:07 2025 +0200
@@ -0,0 +1,265 @@
+// Copyright (C) 2004-2024 Artifex Software, Inc.
+//
+// This file is part of MuPDF.
+//
+// MuPDF is free software: you can redistribute it and/or modify it under the
+// terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option)
+// any later version.
+//
+// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
+//
+// Alternative licensing terms are available from the licensor.
+// For commercial licensing, see <https://www.artifex.com/> or contact
+// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
+// CA 94129, USA, for further information.
+
+#include "mupdf/fitz.h"
+#include "xps-imp.h"
+
+#include <string.h>
+
+static void xps_init_document(fz_context *ctx, xps_document *doc);
+
+static xps_part *
+xps_new_part(fz_context *ctx, xps_document *doc, char *name, fz_buffer *data)
+{
+	xps_part *part = NULL;
+
+	fz_var(part);
+
+	fz_try(ctx)
+	{
+		part = fz_malloc_struct(ctx, xps_part);
+		part->name = fz_strdup(ctx, name);
+		part->data = data; /* take ownership of buffer */
+	}
+	fz_catch(ctx)
+	{
+		fz_drop_buffer(ctx, data);
+		fz_free(ctx, part);
+		fz_rethrow(ctx);
+	}
+
+	return part;
+}
+
+void
+xps_drop_part(fz_context *ctx, xps_document *doc, xps_part *part)
+{
+	fz_free(ctx, part->name);
+	fz_drop_buffer(ctx, part->data);
+	fz_free(ctx, part);
+}
+
+xps_part *
+xps_read_part(fz_context *ctx, xps_document *doc, char *partname)
+{
+	fz_archive *zip = doc->zip;
+	fz_buffer *buf = NULL;
+	fz_buffer *tmp = NULL;
+	char path[2048];
+	int count;
+	char *name;
+	int seen_last;
+
+	fz_var(buf);
+	fz_var(tmp);
+
+	name = partname;
+	if (name[0] == '/')
+		name ++;
+
+	fz_try(ctx)
+	{
+		/* All in one piece */
+		if (fz_has_archive_entry(ctx, zip, name))
+		{
+			buf = fz_read_archive_entry(ctx, zip, name);
+		}
+
+		/* Assemble all the pieces */
+		else
+		{
+			buf = fz_new_buffer(ctx, 512);
+			seen_last = 0;
+			for (count = 0; !seen_last; ++count)
+			{
+				fz_snprintf(path, sizeof path, "%s/[%d].piece", name, count);
+				if (fz_has_archive_entry(ctx, zip, path))
+				{
+					tmp = fz_read_archive_entry(ctx, zip, path);
+					fz_append_buffer(ctx, buf, tmp);
+					fz_drop_buffer(ctx, tmp);
+					tmp = NULL;
+				}
+				else
+				{
+					fz_snprintf(path, sizeof path, "%s/[%d].last.piece", name, count);
+					if (fz_has_archive_entry(ctx, zip, path))
+					{
+						tmp = fz_read_archive_entry(ctx, zip, path);
+						fz_append_buffer(ctx, buf, tmp);
+						fz_drop_buffer(ctx, tmp);
+						tmp = NULL;
+						seen_last = 1;
+					}
+					else
+						fz_throw(ctx, FZ_ERROR_FORMAT, "cannot find all pieces for part '%s'", partname);
+				}
+			}
+		}
+
+	}
+	fz_catch(ctx)
+	{
+		fz_drop_buffer(ctx, tmp);
+		fz_drop_buffer(ctx, buf);
+		fz_rethrow(ctx);
+	}
+
+	return xps_new_part(ctx, doc, partname, buf);
+}
+
+int
+xps_has_part(fz_context *ctx, xps_document *doc, char *name)
+{
+	char buf[2048];
+	if (name[0] == '/')
+		name++;
+	if (fz_has_archive_entry(ctx, doc->zip, name))
+		return 1;
+	fz_snprintf(buf, sizeof buf, "%s/[0].piece", name);
+	if (fz_has_archive_entry(ctx, doc->zip, buf))
+		return 1;
+	fz_snprintf(buf, sizeof buf, "%s/[0].last.piece", name);
+	if (fz_has_archive_entry(ctx, doc->zip, buf))
+		return 1;
+	return 0;
+}
+
+fz_document *
+xps_open_document_with_directory(fz_context *ctx, fz_archive *dir)
+{
+	xps_document *doc;
+
+	doc = fz_malloc_struct(ctx, xps_document);
+	xps_init_document(ctx, doc);
+
+	fz_try(ctx)
+	{
+		doc->zip = fz_keep_archive(ctx, dir);
+		xps_read_page_list(ctx, doc);
+	}
+	fz_catch(ctx)
+	{
+		fz_drop_document(ctx, &doc->super);
+		fz_rethrow(ctx);
+	}
+
+	return (fz_document*)doc;
+}
+
+fz_document *
+xps_open_document_with_stream(fz_context *ctx, fz_stream *file)
+{
+	xps_document *doc;
+
+	doc = fz_malloc_struct(ctx, xps_document);
+	xps_init_document(ctx, doc);
+
+	fz_try(ctx)
+	{
+		doc->zip = fz_open_zip_archive_with_stream(ctx, file);
+		xps_read_page_list(ctx, doc);
+	}
+	fz_catch(ctx)
+	{
+		fz_drop_document(ctx, &doc->super);
+		fz_rethrow(ctx);
+	}
+
+	return (fz_document*)doc;
+}
+
+fz_document *
+xps_open_document(fz_context *ctx, const char *filename)
+{
+	fz_stream *file;
+	fz_document *doc = NULL;
+
+	if (fz_is_directory(ctx, filename))
+	{
+		fz_archive *dir = fz_open_directory(ctx, filename);
+
+		fz_try(ctx)
+			doc = xps_open_document_with_directory(ctx, dir);
+		fz_always(ctx)
+			fz_drop_archive(ctx, dir);
+		fz_catch(ctx)
+			fz_rethrow(ctx);
+
+		return doc;
+	}
+
+	file = fz_open_file(ctx, filename);
+
+	fz_try(ctx)
+		doc = xps_open_document_with_stream(ctx, file);
+	fz_always(ctx)
+		fz_drop_stream(ctx, file);
+	fz_catch(ctx)
+		fz_rethrow(ctx);
+
+	return (fz_document*)doc;
+}
+
+static void
+xps_drop_document(fz_context *ctx, fz_document *doc_)
+{
+	xps_document *doc = (xps_document*)doc_;
+	xps_font_cache *font, *next;
+
+	if (doc->zip)
+		fz_drop_archive(ctx, doc->zip);
+
+	font = doc->font_table;
+	while (font)
+	{
+		next = font->next;
+		fz_drop_font(ctx, font->font);
+		fz_free(ctx, font->name);
+		fz_free(ctx, font);
+		font = next;
+	}
+
+	xps_drop_page_list(ctx, doc);
+
+	fz_free(ctx, doc->start_part);
+}
+
+static int
+xps_lookup_metadata(fz_context *ctx, fz_document *doc_, const char *key, char *buf, size_t size)
+{
+	if (!strcmp(key, FZ_META_FORMAT))
+		return 1 + (int)fz_strlcpy(buf, "XPS", size);
+	return -1;
+}
+
+static void
+xps_init_document(fz_context *ctx, xps_document *doc)
+{
+	doc->super.refs = 1;
+	doc->super.drop_document = xps_drop_document;
+	doc->super.load_outline = xps_load_outline;
+	doc->super.resolve_link_dest = xps_lookup_link_target;
+	doc->super.count_pages = xps_count_pages;
+	doc->super.load_page = xps_load_page;
+	doc->super.lookup_metadata = xps_lookup_metadata;
+}