diff mupdf-source/source/fitz/stream-open.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/fitz/stream-open.c	Mon Sep 15 11:43:07 2025 +0200
@@ -0,0 +1,384 @@
+// 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.
+
+#define _LARGEFILE_SOURCE
+#ifndef _FILE_OFFSET_BITS
+#define _FILE_OFFSET_BITS 64
+#endif
+
+#include "mupdf/fitz.h"
+
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#include <wchar.h>
+#else
+#include <unistd.h>
+#endif
+
+int
+fz_file_exists(fz_context *ctx, const char *path)
+{
+	FILE *file;
+#ifdef _WIN32
+	file = fz_fopen_utf8(path, "rb");
+#else
+	file = fopen(path, "rb");
+#endif
+	if (file)
+		fclose(file);
+	return !!file;
+}
+
+fz_stream *
+fz_new_stream(fz_context *ctx, void *state, fz_stream_next_fn *next, fz_stream_drop_fn *drop)
+{
+	fz_stream *stm = NULL;
+
+	fz_try(ctx)
+	{
+		stm = fz_malloc_struct(ctx, fz_stream);
+	}
+	fz_catch(ctx)
+	{
+		if (drop)
+			drop(ctx, state);
+		fz_rethrow(ctx);
+	}
+
+	stm->refs = 1;
+	stm->error = 0;
+	stm->eof = 0;
+	stm->pos = 0;
+
+	stm->bits = 0;
+	stm->avail = 0;
+
+	stm->rp = NULL;
+	stm->wp = NULL;
+
+	stm->state = state;
+	stm->next = next;
+	stm->drop = drop;
+	stm->seek = NULL;
+
+	return stm;
+}
+
+fz_stream *
+fz_keep_stream(fz_context *ctx, fz_stream *stm)
+{
+	return fz_keep_imp(ctx, stm, &stm->refs);
+}
+
+void
+fz_drop_stream(fz_context *ctx, fz_stream *stm)
+{
+	if (fz_drop_imp(ctx, stm, &stm->refs))
+	{
+		if (stm->drop)
+			stm->drop(ctx, stm->state);
+		fz_free(ctx, stm);
+	}
+}
+
+/* File stream */
+
+// TODO: WIN32: HANDLE CreateFileW(), etc.
+// TODO: POSIX: int creat(), read(), write(), lseeko, etc.
+
+typedef struct
+{
+	FILE *file;
+	char *filename;
+#ifdef _WIN32
+	wchar_t *filename_w;
+#endif
+	int del_on_drop;
+	unsigned char buffer[4096];
+} fz_file_stream;
+
+static int next_file(fz_context *ctx, fz_stream *stm, size_t n)
+{
+	fz_file_stream *state = stm->state;
+
+	/* n is only a hint, that we can safely ignore */
+	n = fread(state->buffer, 1, sizeof(state->buffer), state->file);
+	if (n < sizeof(state->buffer) && ferror(state->file))
+		fz_throw(ctx, FZ_ERROR_SYSTEM, "read error: %s", strerror(errno));
+	stm->rp = state->buffer;
+	stm->wp = state->buffer + n;
+	stm->pos += (int64_t)n;
+
+	if (n == 0)
+		return EOF;
+	return *stm->rp++;
+}
+
+static void seek_file(fz_context *ctx, fz_stream *stm, int64_t offset, int whence)
+{
+	fz_file_stream *state = stm->state;
+#ifdef _WIN32
+	int64_t n = _fseeki64(state->file, offset, whence);
+#else
+	int64_t n = fseeko(state->file, offset, whence);
+#endif
+	if (n < 0)
+		fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot seek: %s", strerror(errno));
+#ifdef _WIN32
+	stm->pos = _ftelli64(state->file);
+#else
+	stm->pos = ftello(state->file);
+#endif
+	stm->rp = state->buffer;
+	stm->wp = state->buffer;
+}
+
+static void drop_file(fz_context *ctx, void *state_)
+{
+	fz_file_stream *state = state_;
+	if (state->filename && state->del_on_drop)
+	{
+#ifdef _WIN32
+		if (state->filename_w)
+			_wunlink(state->filename_w);
+		else
+#endif
+		unlink(state->filename);
+	}
+#ifdef _WIN32
+	fz_free(ctx, state->filename_w);
+#endif
+	fz_free(ctx, state->filename);
+	fz_free(ctx, state);
+}
+
+static void close_and_drop_file(fz_context *ctx, void *state_)
+{
+	fz_file_stream *state = state_;
+	if (state)
+	{
+		int n = fclose(state->file);
+		if (n < 0)
+			fz_warn(ctx, "close error: %s", strerror(errno));
+		drop_file(ctx, state_);
+	}
+}
+
+static fz_stream *
+fz_open_file_ptr(fz_context *ctx, FILE *file, const char *name, int wide, int del_on_drop)
+{
+	fz_stream *stm;
+	fz_file_stream *state = NULL;
+
+	fz_var(state);
+
+#ifndef _WIN32
+	assert(!wide);
+#endif
+	fz_try(ctx)
+	{
+		state = fz_malloc_struct(ctx, fz_file_stream);
+		state->file = file;
+#ifdef _WIN32
+		if (wide)
+		{
+			size_t z = wcslen((const wchar_t *)name)+1;
+			state->filename_w = fz_malloc(ctx, z*2);
+			memcpy(state->filename_w, name, z*2);
+			state->filename = fz_utf8_from_wchar(ctx, (const wchar_t *)name);
+		}
+		else
+#endif
+		state->filename = fz_strdup(ctx, name);
+		state->del_on_drop = del_on_drop;
+
+		stm = fz_new_stream(ctx, state, next_file, close_and_drop_file);
+		stm->seek = seek_file;
+	}
+	fz_catch(ctx)
+	{
+		if (state == NULL && del_on_drop)
+		{
+			fclose(file);
+#ifdef _WIN32
+			if (wide)
+				_wunlink((const wchar_t *)name);
+			else
+#endif
+				unlink(name);
+		}
+		else
+			close_and_drop_file(ctx, state);
+		fz_rethrow(ctx);
+	}
+
+	return stm;
+}
+
+fz_stream *fz_open_file_ptr_no_close(fz_context *ctx, FILE *file)
+{
+	fz_stream *stm;
+	fz_file_stream *state = fz_malloc_struct(ctx, fz_file_stream);
+	state->file = file;
+
+	/* We don't own the file ptr. Ensure we don't close it */
+	stm = fz_new_stream(ctx, state, next_file, drop_file);
+	stm->seek = seek_file;
+
+	return stm;
+}
+
+fz_stream *
+fz_open_file(fz_context *ctx, const char *name)
+{
+	FILE *file;
+#ifdef _WIN32
+	file = fz_fopen_utf8(name, "rb");
+#else
+	file = fopen(name, "rb");
+#endif
+	if (file == NULL)
+		fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot open %s: %s", name, strerror(errno));
+	return fz_open_file_ptr(ctx, file, name, 0, 0);
+}
+
+fz_stream *
+fz_open_file_autodelete(fz_context *ctx, const char *name)
+{
+	FILE *file;
+#ifdef _WIN32
+	file = fz_fopen_utf8(name, "rb");
+#else
+	file = fopen(name, "rb");
+#endif
+	if (file == NULL)
+		fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot open %s: %s", name, strerror(errno));
+	return fz_open_file_ptr(ctx, file, name, 0, 1);
+}
+
+fz_stream *
+fz_try_open_file(fz_context *ctx, const char *name)
+{
+	FILE *file;
+#ifdef _WIN32
+	file = fz_fopen_utf8(name, "rb");
+#else
+	file = fopen(name, "rb");
+#endif
+	if (file == NULL)
+		return NULL;
+	return fz_open_file_ptr(ctx, file, name, 0, 0);
+}
+
+#ifdef _WIN32
+fz_stream *
+fz_open_file_w(fz_context *ctx, const wchar_t *name)
+{
+	FILE *file = _wfopen(name, L"rb");
+	if (file == NULL)
+		fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot open file %ls: %s", name, strerror(errno));
+
+	return fz_open_file_ptr(ctx, file, (const char *)name, 1, 0);
+}
+#endif
+
+const char *
+fz_stream_filename(fz_context *ctx, fz_stream *stm)
+{
+	if (!stm || stm->next != next_file)
+		return NULL;
+
+	return ((fz_file_stream *)stm->state)->filename;
+}
+
+/* Memory stream */
+
+static int next_buffer(fz_context *ctx, fz_stream *stm, size_t max)
+{
+	return EOF;
+}
+
+static void seek_buffer(fz_context *ctx, fz_stream *stm, int64_t offset, int whence)
+{
+	int64_t pos = stm->pos - (stm->wp - stm->rp);
+	/* Convert to absolute pos */
+	if (whence == 1)
+	{
+		offset += pos; /* Was relative to current pos */
+	}
+	else if (whence == 2)
+	{
+		offset += stm->pos; /* Was relative to end */
+	}
+
+	if (offset < 0)
+		offset = 0;
+	if (offset > stm->pos)
+		offset = stm->pos;
+	stm->rp += (int)(offset - pos);
+}
+
+static void drop_buffer(fz_context *ctx, void *state_)
+{
+	fz_buffer *state = (fz_buffer *)state_;
+	fz_drop_buffer(ctx, state);
+}
+
+fz_stream *
+fz_open_buffer(fz_context *ctx, fz_buffer *buf)
+{
+	fz_stream *stm;
+
+	if (buf == NULL)
+		return NULL;
+
+	fz_keep_buffer(ctx, buf);
+	stm = fz_new_stream(ctx, buf, next_buffer, drop_buffer);
+	stm->seek = seek_buffer;
+
+	stm->rp = buf->data;
+	stm->wp = buf->data + buf->len;
+
+	stm->pos = (int64_t)buf->len;
+
+	return stm;
+}
+
+fz_stream *
+fz_open_memory(fz_context *ctx, const unsigned char *data, size_t len)
+{
+	fz_stream *stm;
+
+	stm = fz_new_stream(ctx, NULL, next_buffer, NULL);
+	stm->seek = seek_buffer;
+
+	stm->rp = (unsigned char *)data;
+	stm->wp = (unsigned char *)data + len;
+
+	stm->pos = (int64_t)len;
+
+	return stm;
+}