diff mupdf-source/source/fitz/encode-basic.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/encode-basic.c	Mon Sep 15 11:43:07 2025 +0200
@@ -0,0 +1,492 @@
+// Copyright (C) 2004-2025 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 "z-imp.h"
+
+#include <limits.h>
+
+struct ahx
+{
+	fz_output *chain;
+	int column;
+};
+
+static void ahx_write(fz_context *ctx, void *opaque, const void *data, size_t n)
+{
+	static const char tohex[17] = "0123456789ABCDEF";
+	struct ahx *state = opaque;
+	const unsigned char *p = data;
+	while (n-- > 0)
+	{
+		int c = *p++;
+		fz_write_byte(ctx, state->chain, tohex[(c>>4) & 15]);
+		fz_write_byte(ctx, state->chain, tohex[(c) & 15]);
+		state->column += 2;
+		if (state->column == 64)
+		{
+			fz_write_byte(ctx, state->chain, '\n');
+			state->column = 0;
+		}
+	}
+}
+
+static void ahx_close(fz_context *ctx, void *opaque)
+{
+	struct ahx *state = opaque;
+	fz_write_byte(ctx, state->chain, '>');
+}
+
+static void ahx_reset(fz_context *ctx, void *opaque)
+{
+	struct ahx *state = opaque;
+	state->column = 0;
+	fz_reset_output(ctx, state->chain);
+}
+
+static void ahx_drop(fz_context *ctx, void *opaque)
+{
+	struct ahx *state = opaque;
+	fz_free(ctx, state);
+}
+
+fz_output *
+fz_new_asciihex_output(fz_context *ctx, fz_output *chain)
+{
+	fz_output *out;
+	struct ahx *state = fz_malloc_struct(ctx, struct ahx);
+
+	state->chain = chain;
+	state->column = 0;
+	out = fz_new_output(ctx, 512, state, ahx_write, ahx_close, ahx_drop);
+	out->reset = ahx_reset;
+
+	return out;
+}
+
+struct a85
+{
+	fz_output *chain;
+	int column;
+	unsigned int word, n;
+};
+
+static void a85_flush(fz_context *ctx, struct a85 *state)
+{
+	unsigned int v1, v2, v3, v4, v5;
+
+	v5 = state->word;
+	v4 = v5 / 85;
+	v3 = v4 / 85;
+	v2 = v3 / 85;
+	v1 = v2 / 85;
+
+	if (state->column >= 70)
+	{
+		fz_write_byte(ctx, state->chain, '\n');
+		state->column = 0;
+	}
+
+	if (state->n == 4)
+	{
+		if (state->word == 0)
+		{
+			fz_write_byte(ctx, state->chain, 'z');
+			state->column += 1;
+		}
+		else
+		{
+			fz_write_byte(ctx, state->chain, (v1 % 85) + '!');
+			fz_write_byte(ctx, state->chain, (v2 % 85) + '!');
+			fz_write_byte(ctx, state->chain, (v3 % 85) + '!');
+			fz_write_byte(ctx, state->chain, (v4 % 85) + '!');
+			fz_write_byte(ctx, state->chain, (v5 % 85) + '!');
+			state->column += 5;
+		}
+	}
+	else if (state->n == 3)
+	{
+		fz_write_byte(ctx, state->chain, (v2 % 85) + '!');
+		fz_write_byte(ctx, state->chain, (v3 % 85) + '!');
+		fz_write_byte(ctx, state->chain, (v4 % 85) + '!');
+		fz_write_byte(ctx, state->chain, (v5 % 85) + '!');
+		state->column += 4;
+	}
+	else if (state->n == 2)
+	{
+		fz_write_byte(ctx, state->chain, (v3 % 85) + '!');
+		fz_write_byte(ctx, state->chain, (v4 % 85) + '!');
+		fz_write_byte(ctx, state->chain, (v5 % 85) + '!');
+		state->column += 3;
+	}
+	else if (state->n == 1)
+	{
+		fz_write_byte(ctx, state->chain, (v4 % 85) + '!');
+		fz_write_byte(ctx, state->chain, (v5 % 85) + '!');
+		state->column += 2;
+	}
+
+	state->word = 0;
+	state->n = 0;
+}
+
+static void a85_write(fz_context *ctx, void *opaque, const void *data, size_t n)
+{
+	struct a85 *state = opaque;
+	const unsigned char *p = data;
+	while (n-- > 0)
+	{
+		unsigned int c = *p++;
+		if (state->n == 4)
+			a85_flush(ctx, state);
+		state->word = (state->word << 8) | c;
+		state->n++;
+	}
+}
+
+static void a85_close(fz_context *ctx, void *opaque)
+{
+	struct a85 *state = opaque;
+	a85_flush(ctx, state);
+	fz_write_byte(ctx, state->chain, '~');
+	fz_write_byte(ctx, state->chain, '>');
+}
+
+static void a85_reset(fz_context *ctx, void *opaque)
+{
+	struct a85 *state = opaque;
+	state->column = 0;
+	state->word = 0;
+	state->n = 0;
+	fz_reset_output(ctx, state->chain);
+}
+
+static void a85_drop(fz_context *ctx, void *opaque)
+{
+	struct a85 *state = opaque;
+	fz_free(ctx, state);
+}
+
+fz_output *
+fz_new_ascii85_output(fz_context *ctx, fz_output *chain)
+{
+	fz_output *out;
+	struct a85 *state = fz_malloc_struct(ctx, struct a85);
+
+	state->chain = chain;
+	state->column = 0;
+	state->word = 0;
+	state->n = 0;
+	out = fz_new_output(ctx, 512, state, a85_write, a85_close, a85_drop);
+	out->reset = a85_reset;
+
+	return out;
+}
+
+struct rle
+{
+	fz_output *chain;
+	int state;
+	int run;
+	unsigned char buf[128];
+};
+
+enum { ZERO, ONE, DIFF, SAME };
+
+static void rle_flush_same(fz_context *ctx, struct rle *enc)
+{
+	fz_write_byte(ctx, enc->chain, 257 - enc->run);
+	fz_write_byte(ctx, enc->chain, enc->buf[0]);
+}
+
+static void rle_flush_diff(fz_context *ctx, struct rle *enc)
+{
+	fz_write_byte(ctx, enc->chain, enc->run - 1);
+	fz_write_data(ctx, enc->chain, enc->buf, enc->run);
+}
+
+static void rle_write(fz_context *ctx, void *opaque, const void *data, size_t n)
+{
+	struct rle *enc = opaque;
+	const unsigned char *p = data;
+	while (n-- > 0)
+	{
+		int c = *p++;
+		switch (enc->state)
+		{
+		case ZERO:
+			enc->state = ONE;
+			enc->run = 1;
+			enc->buf[0] = c;
+			break;
+
+		case ONE:
+			enc->state = DIFF;
+			enc->run = 2;
+			enc->buf[1] = c;
+			break;
+
+		case DIFF:
+			/* Max run length */
+			if (enc->run == 128)
+			{
+				rle_flush_diff(ctx, enc);
+				enc->state = ONE;
+				enc->run = 1;
+				enc->buf[0] = c;
+			}
+			/* Run of three same */
+			else if ((enc->run >= 2) && (c == enc->buf[enc->run-1]) && (c == enc->buf[enc->run-2]))
+			{
+				if (enc->run >= 3) {
+					enc->run -= 2; /* skip last two in previous run */
+					rle_flush_diff(ctx, enc);
+				}
+				enc->state = SAME;
+				enc->run = 3;
+				enc->buf[0] = c;
+			}
+			else
+			{
+				enc->buf[enc->run] = c;
+				enc->run++;
+			}
+			break;
+
+		case SAME:
+			if ((enc->run == 128) || (c != enc->buf[0]))
+			{
+				rle_flush_same(ctx, enc);
+				enc->state = ONE;
+				enc->run = 1;
+				enc->buf[0] = c;
+			}
+			else
+			{
+				enc->run++;
+			}
+		}
+	}
+}
+
+static void rle_close(fz_context *ctx, void *opaque)
+{
+	struct rle *enc = opaque;
+	switch (enc->state)
+	{
+		case ZERO: break;
+		case ONE: rle_flush_diff(ctx, enc); break;
+		case DIFF: rle_flush_diff(ctx, enc); break;
+		case SAME: rle_flush_same(ctx, enc); break;
+	}
+	fz_write_byte(ctx, enc->chain, 128);
+}
+
+static void rle_reset(fz_context *ctx, void *opaque)
+{
+	struct rle *enc = opaque;
+	enc->state = ZERO;
+	enc->run = 0;
+	fz_reset_output(ctx, enc->chain);
+}
+
+static void rle_drop(fz_context *ctx, void *opaque)
+{
+	struct rle *enc = opaque;
+	fz_free(ctx, enc);
+}
+
+fz_output *
+fz_new_rle_output(fz_context *ctx, fz_output *chain)
+{
+	fz_output *out;
+	struct rle *enc = fz_malloc_struct(ctx, struct rle);
+
+	enc->chain = chain;
+	enc->state = ZERO;
+	enc->run = 0;
+	out = fz_new_output(ctx, 4096, enc, rle_write, rle_close, rle_drop);
+	out->reset = rle_reset;
+
+	return out;
+}
+
+struct arc4
+{
+	fz_output *chain;
+	fz_arc4 arc4;
+	fz_arc4 arc4_orig;
+};
+
+static void arc4_write(fz_context *ctx, void *opaque, const void *data, size_t n)
+{
+	struct arc4 *state = opaque;
+	const unsigned char *p = data;
+	unsigned char buffer[256];
+	while (n > 0)
+	{
+		size_t x = (n > sizeof buffer) ? sizeof buffer : n;
+		fz_arc4_encrypt(&state->arc4, buffer, p, x);
+		fz_write_data(ctx, state->chain, buffer, x);
+		p += x;
+		n -= x;
+	}
+}
+
+static void arc4_reset(fz_context *ctx, void *opaque)
+{
+	struct arc4 *state = opaque;
+	memcpy(&state->arc4, &state->arc4_orig, sizeof(state->arc4));
+	fz_reset_output(ctx, state->chain);
+}
+
+static void arc4_drop(fz_context *ctx, void *opaque)
+{
+	fz_free(ctx, opaque);
+}
+
+fz_output *
+fz_new_arc4_output(fz_context *ctx, fz_output *chain, unsigned char *key, size_t keylen)
+{
+	fz_output *out;
+	struct arc4 *state = fz_malloc_struct(ctx, struct arc4);
+
+	state->chain = chain;
+	fz_arc4_init(&state->arc4, key, keylen);
+	memcpy(&state->arc4_orig, &state->arc4, sizeof(state->arc4));
+	out = fz_new_output(ctx, 256, state, arc4_write, NULL, arc4_drop);
+	out->reset = arc4_reset;
+
+	return out;
+}
+
+struct deflate
+{
+	fz_output *chain;
+	z_stream z;
+	uInt bufsize;
+	unsigned char *buf;
+};
+
+static void deflate_write(fz_context *ctx, void *opaque, const void *data, size_t n)
+{
+	struct deflate *state = opaque;
+	const unsigned char *p = data;
+	uLong newbufsizeLong;
+	uInt newbufsize;
+	int err;
+
+	newbufsizeLong = n >= UINT_MAX ? UINT_MAX : deflateBound(&state->z, (uLong)n);
+	newbufsize = (uInt)(newbufsizeLong >= UINT_MAX ? UINT_MAX : newbufsizeLong);
+
+	if (state->buf == NULL)
+	{
+		state->buf = Memento_label(fz_malloc(ctx, newbufsize), "deflate_buffer");
+		state->bufsize = newbufsize;
+	}
+	else if (newbufsize > state->bufsize)
+	{
+		state->buf = Memento_label(fz_realloc(ctx, state->buf, newbufsize), "deflate_buffer");
+		state->bufsize = newbufsize;
+	}
+
+	while (n > 0)
+	{
+		state->z.avail_in = n <= UINT_MAX ? (uInt)n : UINT_MAX;
+		state->z.next_in = (unsigned char *) p;
+		n -= state->z.avail_in;
+		p += state->z.avail_in;
+
+		do
+		{
+			state->z.next_out = state->buf;
+			state->z.avail_out = state->bufsize;
+			err = deflate(&state->z, Z_NO_FLUSH);
+			if (err != Z_OK)
+				fz_throw(ctx, FZ_ERROR_LIBRARY, "zlib compression failed: %d", err);
+			if (state->z.avail_out < state->bufsize)
+				fz_write_data(ctx, state->chain, state->buf, state->bufsize - state->z.avail_out);
+		} while (state->z.avail_in > 0);
+	}
+}
+
+static void deflate_close(fz_context *ctx, void *opaque)
+{
+	struct deflate *state = opaque;
+	int err;
+
+	state->z.next_in = NULL;
+	state->z.avail_in = 0;
+	do
+	{
+		state->z.next_out = state->buf;
+		state->z.avail_out = state->bufsize;
+		err = deflate(&state->z, Z_FINISH);
+		if (state->z.avail_out < state->bufsize)
+			fz_write_data(ctx, state->chain, state->buf, state->bufsize - state->z.avail_out);
+	} while (err == Z_OK);
+
+	if (err != Z_STREAM_END)
+		fz_throw(ctx, FZ_ERROR_LIBRARY, "zlib compression failed: %d", err);
+}
+
+static void deflate_reset(fz_context *ctx, void *opaque)
+{
+	struct deflate *state = opaque;
+	int err = deflateReset(&state->z);
+	if (err != Z_OK)
+		fz_throw(ctx, FZ_ERROR_LIBRARY, "zlib reset failed: %d", err);
+	fz_reset_output(ctx, state->chain);
+}
+
+static void deflate_drop(fz_context *ctx, void *opaque)
+{
+	struct deflate *state = opaque;
+	(void)deflateEnd(&state->z);
+	fz_free(ctx, state->buf);
+	fz_free(ctx, state);
+}
+
+fz_output *
+fz_new_deflate_output(fz_context *ctx, fz_output *chain, int effort, int raw)
+{
+	fz_output *out;
+	int err;
+	struct deflate *state = fz_malloc_struct(ctx, struct deflate);
+
+	state->chain = chain;
+	state->z.opaque = ctx;
+	state->z.zalloc = fz_zlib_alloc;
+	state->z.zfree = fz_zlib_free;
+	err = deflateInit2(&state->z, effort, Z_DEFLATED, raw ? -15 : 15, 8, Z_DEFAULT_STRATEGY);
+	if (err != Z_OK)
+	{
+		(void)deflateEnd(&state->z);
+		fz_free(ctx, state);
+		fz_throw(ctx, FZ_ERROR_LIBRARY, "zlib deflateInit2 failed: %d", err);
+	}
+	out = fz_new_output(ctx, 8192, state, deflate_write, deflate_close, deflate_drop);
+	out->reset = deflate_reset;
+
+	return out;
+}