| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860 |
- // 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.
- #define _LARGEFILE_SOURCE
- #ifndef _FILE_OFFSET_BITS
- #define _FILE_OFFSET_BITS 64
- #endif
- #include "mupdf/fitz.h"
- #include <errno.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <string.h>
- #ifdef _WIN32
- #include <io.h>
- #include <windows.h>
- #else
- #include <unistd.h>
- #endif
- static void
- file_write(fz_context *ctx, void *opaque, const void *buffer, size_t count)
- {
- FILE *file = opaque;
- size_t n;
- if (count == 0)
- return;
- if (count == 1)
- {
- int x = putc(((unsigned char*)buffer)[0], file);
- if (x == EOF && ferror(file))
- fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot fwrite: %s", strerror(errno));
- return;
- }
- n = fwrite(buffer, 1, count, file);
- if (n < count && ferror(file))
- fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot fwrite: %s", strerror(errno));
- }
- static void
- stdout_write(fz_context *ctx, void *opaque, const void *buffer, size_t count)
- {
- file_write(ctx, stdout, buffer, count);
- }
- static fz_output fz_stdout_global = {
- NULL,
- stdout_write,
- NULL,
- NULL,
- NULL,
- };
- fz_output *fz_stdout(fz_context *ctx)
- {
- return &fz_stdout_global;
- }
- static void
- stderr_write(fz_context *ctx, void *opaque, const void *buffer, size_t count)
- {
- file_write(ctx, stderr, buffer, count);
- }
- static fz_output fz_stderr_global = {
- NULL,
- stderr_write,
- NULL,
- NULL,
- NULL,
- };
- fz_output *fz_stderr(fz_context *ctx)
- {
- return &fz_stderr_global;
- }
- #ifdef _WIN32
- static void
- stdods_write(fz_context *ctx, void *opaque, const void *buffer, size_t count)
- {
- char *buf = fz_malloc(ctx, count+1);
- memcpy(buf, buffer, count);
- buf[count] = 0;
- OutputDebugStringA(buf);
- fz_free(ctx, buf);
- }
- static fz_output fz_stdods_global = {
- NULL,
- stdods_write,
- NULL,
- NULL,
- NULL,
- };
- fz_output *fz_stdods(fz_context *ctx)
- {
- return &fz_stdods_global;
- }
- #endif
- fz_output *fz_stddbg(fz_context *ctx)
- {
- if (ctx->stddbg)
- return ctx->stddbg;
- return fz_stderr(ctx);
- }
- void fz_set_stddbg(fz_context *ctx, fz_output *out)
- {
- if (ctx == NULL)
- return;
- ctx->stddbg = out;
- }
- static void
- file_seek(fz_context *ctx, void *opaque, int64_t off, int whence)
- {
- FILE *file = opaque;
- #ifdef _WIN32
- int n = _fseeki64(file, off, whence);
- #else
- int n = fseeko(file, off, whence);
- #endif
- if (n < 0)
- fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot fseek: %s", strerror(errno));
- }
- static int64_t
- file_tell(fz_context *ctx, void *opaque)
- {
- FILE *file = opaque;
- #ifdef _WIN32
- int64_t off = _ftelli64(file);
- #else
- int64_t off = ftello(file);
- #endif
- if (off == -1)
- fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot ftell: %s", strerror(errno));
- return off;
- }
- static void
- file_drop(fz_context *ctx, void *opaque)
- {
- FILE *file = opaque;
- int n = fclose(file);
- if (n < 0)
- fz_warn(ctx, "cannot fclose: %s", strerror(errno));
- }
- static fz_stream *
- file_as_stream(fz_context *ctx, void *opaque)
- {
- FILE *file = opaque;
- fflush(file);
- return fz_open_file_ptr_no_close(ctx, file);
- }
- static void file_truncate(fz_context *ctx, void *opaque)
- {
- FILE *file = opaque;
- fflush(file);
- #ifdef _WIN32
- {
- __int64 pos = _ftelli64(file);
- if (pos >= 0)
- _chsize_s(fileno(file), pos);
- }
- #else
- {
- off_t pos = ftello(file);
- if (pos >= 0)
- (void)ftruncate(fileno(file), pos);
- }
- #endif
- }
- fz_output *
- fz_new_output(fz_context *ctx, int bufsiz, void *state, fz_output_write_fn *write, fz_output_close_fn *close, fz_output_drop_fn *drop)
- {
- fz_output *out = NULL;
- fz_var(out);
- fz_try(ctx)
- {
- out = fz_malloc_struct(ctx, fz_output);
- out->state = state;
- out->write = write;
- out->close = close;
- out->drop = drop;
- if (bufsiz > 0)
- {
- out->bp = Memento_label(fz_malloc(ctx, bufsiz), "output_buf");
- out->wp = out->bp;
- out->ep = out->bp + bufsiz;
- }
- }
- fz_catch(ctx)
- {
- if (drop)
- drop(ctx, state);
- fz_free(ctx, out);
- fz_rethrow(ctx);
- }
- return out;
- }
- static void null_write(fz_context *ctx, void *opaque, const void *buffer, size_t count)
- {
- }
- fz_output *
- fz_new_output_with_path(fz_context *ctx, const char *filename, int append)
- {
- FILE *file;
- if (filename == NULL)
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "no output to write to");
- if (!strcmp(filename, "/dev/null") || !fz_strcasecmp(filename, "nul:"))
- return fz_new_output(ctx, 0, NULL, null_write, NULL, NULL);
- /* If <append> is false, we use fopen()'s 'x' flag to force an error if
- * some other process creates the file immediately after we have removed
- * it - this avoids vulnerability where a less-privilege process can create
- * a link and get us to overwrite a different file. See:
- * https://bugs.ghostscript.com/show_bug.cgi?id=701797
- * http://www.open-std.org/jtc1/sc22//WG14/www/docs/n1339.pdf
- */
- #ifdef _WIN32
- /* Ensure we create a brand new file. We don't want to clobber our old file. */
- if (!append)
- {
- if (fz_remove_utf8(filename) < 0)
- if (errno != ENOENT)
- fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot remove file '%s': %s", filename, strerror(errno));
- }
- #if defined(__MINGW32__) || defined(__MINGW64__)
- file = fz_fopen_utf8(filename, append ? "rb+" : "wb+"); /* 'x' flag not supported. */
- #else
- file = fz_fopen_utf8(filename, append ? "rb+" : "wb+x");
- #endif
- if (append)
- {
- if (file == NULL)
- file = fz_fopen_utf8(filename, "wb+");
- else
- fseek(file, 0, SEEK_END);
- }
- #else
- /* Ensure we create a brand new file. We don't want to clobber our old file. */
- if (!append)
- {
- if (remove(filename) < 0)
- if (errno != ENOENT)
- fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot remove file '%s': %s", filename, strerror(errno));
- }
- file = fopen(filename, append ? "rb+" : "wb+x");
- if (file == NULL && append)
- file = fopen(filename, "wb+");
- #endif
- if (!file)
- fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot open file '%s': %s", filename, strerror(errno));
- return fz_new_output_with_file_ptr(ctx, file);
- }
- fz_output *
- fz_new_output_with_file_ptr(fz_context *ctx, FILE *file)
- {
- fz_output *out;
- if (!file)
- return fz_new_output(ctx, 0, NULL, null_write, NULL, NULL);
- setvbuf(file, NULL, _IONBF, 0); /* we do our own buffering */
- out = fz_new_output(ctx, 8192, file, file_write, NULL, file_drop);
- out->seek = file_seek;
- out->tell = file_tell;
- out->as_stream = file_as_stream;
- out->truncate = file_truncate;
- return out;
- }
- static void
- buffer_write(fz_context *ctx, void *opaque, const void *data, size_t len)
- {
- fz_buffer *buffer = opaque;
- fz_append_data(ctx, buffer, data, len);
- }
- static void
- buffer_seek(fz_context *ctx, void *opaque, int64_t off, int whence)
- {
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot seek in buffer: %s", strerror(errno));
- }
- static int64_t
- buffer_tell(fz_context *ctx, void *opaque)
- {
- fz_buffer *buffer = opaque;
- return (int64_t)buffer->len;
- }
- static void
- buffer_drop(fz_context *ctx, void *opaque)
- {
- fz_buffer *buffer = opaque;
- fz_drop_buffer(ctx, buffer);
- }
- static void
- buffer_reset(fz_context *ctx, void *opaque)
- {
- }
- fz_output *
- fz_new_output_with_buffer(fz_context *ctx, fz_buffer *buf)
- {
- fz_output *out = fz_new_output(ctx, 0, fz_keep_buffer(ctx, buf), buffer_write, NULL, buffer_drop);
- out->seek = buffer_seek;
- out->tell = buffer_tell;
- out->reset = buffer_reset;
- return out;
- }
- void
- fz_close_output(fz_context *ctx, fz_output *out)
- {
- if (out == NULL)
- return;
- fz_flush_output(ctx, out);
- if (!out->closed && out->close)
- out->close(ctx, out->state);
- out->closed = 1;
- }
- void
- fz_drop_output(fz_context *ctx, fz_output *out)
- {
- if (out)
- {
- if (!out->closed)
- fz_warn(ctx, "dropping unclosed output");
- if (out->drop)
- out->drop(ctx, out->state);
- fz_free(ctx, out->bp);
- if (out != &fz_stdout_global && out != &fz_stderr_global)
- fz_free(ctx, out);
- }
- }
- void
- fz_reset_output(fz_context *ctx, fz_output *out)
- {
- if (!out)
- return;
- if (out->reset == NULL)
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "Cannot reset this output");
- out->reset(ctx, out->state);
- out->closed = 0;
- }
- void
- fz_seek_output(fz_context *ctx, fz_output *out, int64_t off, int whence)
- {
- if (out->seek == NULL)
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "Cannot seek in unseekable output stream\n");
- fz_flush_output(ctx, out);
- out->seek(ctx, out->state, off, whence);
- }
- int64_t
- fz_tell_output(fz_context *ctx, fz_output *out)
- {
- if (out->tell == NULL)
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "Cannot tell in untellable output stream\n");
- if (out->bp)
- return out->tell(ctx, out->state) + (out->wp - out->bp);
- return out->tell(ctx, out->state);
- }
- fz_stream *
- fz_stream_from_output(fz_context *ctx, fz_output *out)
- {
- if (out->as_stream == NULL)
- return NULL;
- fz_flush_output(ctx, out);
- return out->as_stream(ctx, out->state);
- }
- void
- fz_truncate_output(fz_context *ctx, fz_output *out)
- {
- if (out->truncate == NULL)
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "Cannot truncate this output stream");
- fz_flush_output(ctx, out);
- out->truncate(ctx, out->state);
- }
- static void
- fz_write_emit(fz_context *ctx, void *out, int c)
- {
- fz_write_byte(ctx, out, c);
- }
- void
- fz_write_vprintf(fz_context *ctx, fz_output *out, const char *fmt, va_list args)
- {
- fz_format_string(ctx, out, fz_write_emit, fmt, args);
- }
- void
- fz_write_printf(fz_context *ctx, fz_output *out, const char *fmt, ...)
- {
- va_list args;
- va_start(args, fmt);
- fz_format_string(ctx, out, fz_write_emit, fmt, args);
- va_end(args);
- }
- void
- fz_flush_output(fz_context *ctx, fz_output *out)
- {
- fz_write_bits_sync(ctx, out);
- if (out->wp > out->bp)
- {
- out->write(ctx, out->state, out->bp, out->wp - out->bp);
- out->wp = out->bp;
- }
- }
- void
- fz_write_byte(fz_context *ctx, fz_output *out, unsigned char x)
- {
- if (out->bp)
- {
- if (out->wp == out->ep)
- {
- out->write(ctx, out->state, out->bp, out->wp - out->bp);
- out->wp = out->bp;
- }
- *out->wp++ = x;
- }
- else
- {
- out->write(ctx, out->state, &x, 1);
- }
- }
- void
- fz_write_char(fz_context *ctx, fz_output *out, char x)
- {
- fz_write_byte(ctx, out, (unsigned char)x);
- }
- void
- fz_write_data(fz_context *ctx, fz_output *out, const void *data_, size_t size)
- {
- const char *data = data_;
- if (out->bp)
- {
- if (size >= (size_t) (out->ep - out->bp)) /* too large for buffer */
- {
- if (out->wp > out->bp)
- {
- out->write(ctx, out->state, out->bp, out->wp - out->bp);
- out->wp = out->bp;
- }
- out->write(ctx, out->state, data, size);
- }
- else if (out->wp + size <= out->ep) /* fits in current buffer */
- {
- memcpy(out->wp, data, size);
- out->wp += size;
- }
- else /* fits if we flush first */
- {
- size_t n = out->ep - out->wp;
- memcpy(out->wp, data, n);
- out->write(ctx, out->state, out->bp, out->ep - out->bp);
- memcpy(out->bp, data + n, size - n);
- out->wp = out->bp + size - n;
- }
- }
- else
- {
- out->write(ctx, out->state, data, size);
- }
- }
- void
- fz_write_buffer(fz_context *ctx, fz_output *out, fz_buffer *buf)
- {
- fz_write_data(ctx, out, buf->data, buf->len);
- }
- void
- fz_write_string(fz_context *ctx, fz_output *out, const char *s)
- {
- fz_write_data(ctx, out, s, strlen(s));
- }
- void
- fz_write_int32_be(fz_context *ctx, fz_output *out, int x)
- {
- char data[4];
- data[0] = x>>24;
- data[1] = x>>16;
- data[2] = x>>8;
- data[3] = x;
- fz_write_data(ctx, out, data, 4);
- }
- void
- fz_write_uint32_be(fz_context *ctx, fz_output *out, unsigned int x)
- {
- fz_write_int32_be(ctx, out, (unsigned int)x);
- }
- void
- fz_write_int32_le(fz_context *ctx, fz_output *out, int x)
- {
- char data[4];
- data[0] = x;
- data[1] = x>>8;
- data[2] = x>>16;
- data[3] = x>>24;
- fz_write_data(ctx, out, data, 4);
- }
- void
- fz_write_uint32_le(fz_context *ctx, fz_output *out, unsigned int x)
- {
- fz_write_int32_le(ctx, out, (int)x);
- }
- void
- fz_write_int16_be(fz_context *ctx, fz_output *out, int x)
- {
- char data[2];
- data[0] = x>>8;
- data[1] = x;
- fz_write_data(ctx, out, data, 2);
- }
- void
- fz_write_uint16_be(fz_context *ctx, fz_output *out, unsigned int x)
- {
- fz_write_int16_be(ctx, out, (int)x);
- }
- void
- fz_write_int16_le(fz_context *ctx, fz_output *out, int x)
- {
- char data[2];
- data[0] = x;
- data[1] = x>>8;
- fz_write_data(ctx, out, data, 2);
- }
- void
- fz_write_uint16_le(fz_context *ctx, fz_output *out, unsigned int x)
- {
- fz_write_int16_le(ctx, out, (int)x);
- }
- void
- fz_write_float_le(fz_context *ctx, fz_output *out, float f)
- {
- union {float f; int32_t i;} u;
- u.f = f;
- fz_write_int32_le(ctx, out, u.i);
- }
- void
- fz_write_float_be(fz_context *ctx, fz_output *out, float f)
- {
- union {float f; int32_t i;} u;
- u.f = f;
- fz_write_int32_be(ctx, out, u.i);
- }
- void
- fz_write_rune(fz_context *ctx, fz_output *out, int rune)
- {
- char data[10];
- fz_write_data(ctx, out, data, fz_runetochar(data, rune));
- }
- void
- fz_write_base64(fz_context *ctx, fz_output *out, const unsigned char *data, size_t size, int newline)
- {
- static const char set[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- size_t i;
- for (i = 0; i + 3 <= size; i += 3)
- {
- int c = data[i];
- int d = data[i+1];
- int e = data[i+2];
- if (newline && (i & 15) == 0)
- fz_write_byte(ctx, out, '\n');
- fz_write_byte(ctx, out, set[c>>2]);
- fz_write_byte(ctx, out, set[((c&3)<<4)|(d>>4)]);
- fz_write_byte(ctx, out, set[((d&15)<<2)|(e>>6)]);
- fz_write_byte(ctx, out, set[e&63]);
- }
- if (size - i == 2)
- {
- int c = data[i];
- int d = data[i+1];
- fz_write_byte(ctx, out, set[c>>2]);
- fz_write_byte(ctx, out, set[((c&3)<<4)|(d>>4)]);
- fz_write_byte(ctx, out, set[((d&15)<<2)]);
- fz_write_byte(ctx, out, '=');
- }
- else if (size - i == 1)
- {
- int c = data[i];
- fz_write_byte(ctx, out, set[c>>2]);
- fz_write_byte(ctx, out, set[((c&3)<<4)]);
- fz_write_byte(ctx, out, '=');
- fz_write_byte(ctx, out, '=');
- }
- }
- void
- fz_write_base64_buffer(fz_context *ctx, fz_output *out, fz_buffer *buf, int newline)
- {
- unsigned char *data;
- size_t size = fz_buffer_storage(ctx, buf, &data);
- fz_write_base64(ctx, out, data, size, newline);
- }
- void
- fz_append_base64(fz_context *ctx, fz_buffer *out, const unsigned char *data, size_t size, int newline)
- {
- static const char set[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- size_t i;
- for (i = 0; i + 3 <= size; i += 3)
- {
- int c = data[i];
- int d = data[i+1];
- int e = data[i+2];
- if (newline && (i & 15) == 0)
- fz_append_byte(ctx, out, '\n');
- fz_append_byte(ctx, out, set[c>>2]);
- fz_append_byte(ctx, out, set[((c&3)<<4)|(d>>4)]);
- fz_append_byte(ctx, out, set[((d&15)<<2)|(e>>6)]);
- fz_append_byte(ctx, out, set[e&63]);
- }
- if (size - i == 2)
- {
- int c = data[i];
- int d = data[i+1];
- fz_append_byte(ctx, out, set[c>>2]);
- fz_append_byte(ctx, out, set[((c&3)<<4)|(d>>4)]);
- fz_append_byte(ctx, out, set[((d&15)<<2)]);
- fz_append_byte(ctx, out, '=');
- }
- else if (size - i == 1)
- {
- int c = data[i];
- fz_append_byte(ctx, out, set[c>>2]);
- fz_append_byte(ctx, out, set[((c&3)<<4)]);
- fz_append_byte(ctx, out, '=');
- fz_append_byte(ctx, out, '=');
- }
- }
- void
- fz_append_base64_buffer(fz_context *ctx, fz_buffer *out, fz_buffer *buf, int newline)
- {
- unsigned char *data;
- size_t size = fz_buffer_storage(ctx, buf, &data);
- fz_append_base64(ctx, out, data, size, newline);
- }
- void
- fz_save_buffer(fz_context *ctx, fz_buffer *buf, const char *filename)
- {
- fz_output *out = fz_new_output_with_path(ctx, filename, 0);
- fz_try(ctx)
- {
- fz_write_data(ctx, out, buf->data, buf->len);
- fz_close_output(ctx, out);
- }
- fz_always(ctx)
- fz_drop_output(ctx, out);
- fz_catch(ctx)
- fz_rethrow(ctx);
- }
- fz_band_writer *fz_new_band_writer_of_size(fz_context *ctx, size_t size, fz_output *out)
- {
- fz_band_writer *writer = fz_calloc(ctx, size, 1);
- writer->out = out;
- return writer;
- }
- void fz_write_header(fz_context *ctx, fz_band_writer *writer, int w, int h, int n, int alpha, int xres, int yres, int pagenum, fz_colorspace *cs, fz_separations *seps)
- {
- if (writer == NULL || writer->band == NULL)
- return;
- if (w <= 0 || h <= 0 || n <= 0 || alpha < 0 || alpha > 1)
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "Invalid bandwriter header dimensions/setup");
- writer->w = w;
- writer->h = h;
- writer->s = fz_count_active_separations(ctx, seps);
- writer->n = n;
- writer->alpha = alpha;
- writer->xres = xres;
- writer->yres = yres;
- writer->pagenum = pagenum;
- writer->line = 0;
- writer->seps = fz_keep_separations(ctx, seps);
- writer->header(ctx, writer, cs);
- }
- void fz_write_band(fz_context *ctx, fz_band_writer *writer, int stride, int band_height, const unsigned char *samples)
- {
- if (writer == NULL || writer->band == NULL)
- return;
- if (writer->line + band_height > writer->h)
- band_height = writer->h - writer->line;
- if (band_height < 0) {
- fz_throw(ctx, FZ_ERROR_LIMIT, "Too much band data!");
- }
- if (band_height > 0) {
- writer->band(ctx, writer, stride, writer->line, band_height, samples);
- writer->line += band_height;
- }
- if (writer->line == writer->h && writer->trailer) {
- writer->trailer(ctx, writer);
- /* Protect against more band_height == 0 calls */
- writer->line++;
- }
- }
- void fz_close_band_writer(fz_context *ctx, fz_band_writer *writer)
- {
- if (writer == NULL)
- return;
- if (writer->close != NULL)
- writer->close(ctx, writer);
- writer->close = NULL;
- }
- void fz_drop_band_writer(fz_context *ctx, fz_band_writer *writer)
- {
- if (writer == NULL)
- return;
- if (writer->drop != NULL)
- writer->drop(ctx, writer);
- fz_drop_separations(ctx, writer->seps);
- fz_free(ctx, writer);
- }
- int fz_output_supports_stream(fz_context *ctx, fz_output *out)
- {
- return out != NULL && out->as_stream != NULL;
- }
- void fz_write_bits(fz_context *ctx, fz_output *out, unsigned int data, int num_bits)
- {
- while (num_bits)
- {
- /* How many bits will be left in the current byte after we
- * insert these bits? */
- int n = 8 - num_bits - out->buffered;
- if (n >= 0)
- {
- /* We can fit our data in. */
- out->bits |= data << n;
- out->buffered += num_bits;
- num_bits = 0;
- }
- else
- {
- /* There are 8 - out->buffered bits left to be filled. We have
- * num_bits to fill it with, which is more, so we need to throw
- * away the bottom 'num_bits - (8 - out->buffered)' bits. That's
- * num_bits + out->buffered - 8 = -(8 - num_bits - out_buffered) = -n */
- out->bits |= data >> -n;
- data &= ~(out->bits << -n);
- num_bits = -n;
- out->buffered = 8;
- }
- if (out->buffered == 8)
- {
- fz_write_byte(ctx, out, out->bits);
- out->buffered = 0;
- out->bits = 0;
- }
- }
- }
- void fz_write_bits_sync(fz_context *ctx, fz_output *out)
- {
- if (out->buffered == 0)
- return;
- fz_write_bits(ctx, out, 0, 8 - out->buffered);
- }
- void
- fz_write_stream(fz_context *ctx, fz_output *out, fz_stream *in)
- {
- size_t z;
- while ((z = fz_available(ctx, in, 4096)) != 0)
- {
- fz_write_data(ctx, out, in->rp, z);
- in->rp += z;
- }
- }
|