comparison mupdf-source/source/fitz/output.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
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 // Copyright (C) 2004-2025 Artifex Software, Inc.
2 //
3 // This file is part of MuPDF.
4 //
5 // MuPDF is free software: you can redistribute it and/or modify it under the
6 // terms of the GNU Affero General Public License as published by the Free
7 // Software Foundation, either version 3 of the License, or (at your option)
8 // any later version.
9 //
10 // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13 // details.
14 //
15 // You should have received a copy of the GNU Affero General Public License
16 // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
17 //
18 // Alternative licensing terms are available from the licensor.
19 // For commercial licensing, see <https://www.artifex.com/> or contact
20 // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
21 // CA 94129, USA, for further information.
22
23 #define _LARGEFILE_SOURCE
24 #ifndef _FILE_OFFSET_BITS
25 #define _FILE_OFFSET_BITS 64
26 #endif
27
28 #include "mupdf/fitz.h"
29
30 #include <errno.h>
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <string.h>
34 #ifdef _WIN32
35 #include <io.h>
36 #include <windows.h>
37 #else
38 #include <unistd.h>
39 #endif
40
41 static void
42 file_write(fz_context *ctx, void *opaque, const void *buffer, size_t count)
43 {
44 FILE *file = opaque;
45 size_t n;
46
47 if (count == 0)
48 return;
49
50 if (count == 1)
51 {
52 int x = putc(((unsigned char*)buffer)[0], file);
53 if (x == EOF && ferror(file))
54 fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot fwrite: %s", strerror(errno));
55 return;
56 }
57
58 n = fwrite(buffer, 1, count, file);
59 if (n < count && ferror(file))
60 fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot fwrite: %s", strerror(errno));
61 }
62
63 static void
64 stdout_write(fz_context *ctx, void *opaque, const void *buffer, size_t count)
65 {
66 file_write(ctx, stdout, buffer, count);
67 }
68
69 static fz_output fz_stdout_global = {
70 NULL,
71 stdout_write,
72 NULL,
73 NULL,
74 NULL,
75 };
76
77 fz_output *fz_stdout(fz_context *ctx)
78 {
79 return &fz_stdout_global;
80 }
81
82 static void
83 stderr_write(fz_context *ctx, void *opaque, const void *buffer, size_t count)
84 {
85 file_write(ctx, stderr, buffer, count);
86 }
87
88 static fz_output fz_stderr_global = {
89 NULL,
90 stderr_write,
91 NULL,
92 NULL,
93 NULL,
94 };
95
96 fz_output *fz_stderr(fz_context *ctx)
97 {
98 return &fz_stderr_global;
99 }
100
101 #ifdef _WIN32
102 static void
103 stdods_write(fz_context *ctx, void *opaque, const void *buffer, size_t count)
104 {
105 char *buf = fz_malloc(ctx, count+1);
106
107 memcpy(buf, buffer, count);
108 buf[count] = 0;
109 OutputDebugStringA(buf);
110 fz_free(ctx, buf);
111 }
112
113 static fz_output fz_stdods_global = {
114 NULL,
115 stdods_write,
116 NULL,
117 NULL,
118 NULL,
119 };
120
121 fz_output *fz_stdods(fz_context *ctx)
122 {
123 return &fz_stdods_global;
124 }
125 #endif
126
127 fz_output *fz_stddbg(fz_context *ctx)
128 {
129 if (ctx->stddbg)
130 return ctx->stddbg;
131
132 return fz_stderr(ctx);
133 }
134
135 void fz_set_stddbg(fz_context *ctx, fz_output *out)
136 {
137 if (ctx == NULL)
138 return;
139
140 ctx->stddbg = out;
141 }
142
143 static void
144 file_seek(fz_context *ctx, void *opaque, int64_t off, int whence)
145 {
146 FILE *file = opaque;
147 #ifdef _WIN32
148 int n = _fseeki64(file, off, whence);
149 #else
150 int n = fseeko(file, off, whence);
151 #endif
152 if (n < 0)
153 fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot fseek: %s", strerror(errno));
154 }
155
156 static int64_t
157 file_tell(fz_context *ctx, void *opaque)
158 {
159 FILE *file = opaque;
160 #ifdef _WIN32
161 int64_t off = _ftelli64(file);
162 #else
163 int64_t off = ftello(file);
164 #endif
165 if (off == -1)
166 fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot ftell: %s", strerror(errno));
167 return off;
168 }
169
170 static void
171 file_drop(fz_context *ctx, void *opaque)
172 {
173 FILE *file = opaque;
174 int n = fclose(file);
175 if (n < 0)
176 fz_warn(ctx, "cannot fclose: %s", strerror(errno));
177 }
178
179 static fz_stream *
180 file_as_stream(fz_context *ctx, void *opaque)
181 {
182 FILE *file = opaque;
183 fflush(file);
184 return fz_open_file_ptr_no_close(ctx, file);
185 }
186
187 static void file_truncate(fz_context *ctx, void *opaque)
188 {
189 FILE *file = opaque;
190 fflush(file);
191
192 #ifdef _WIN32
193 {
194 __int64 pos = _ftelli64(file);
195 if (pos >= 0)
196 _chsize_s(fileno(file), pos);
197 }
198 #else
199 {
200 off_t pos = ftello(file);
201 if (pos >= 0)
202 (void)ftruncate(fileno(file), pos);
203 }
204 #endif
205 }
206
207 fz_output *
208 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)
209 {
210 fz_output *out = NULL;
211
212 fz_var(out);
213
214 fz_try(ctx)
215 {
216 out = fz_malloc_struct(ctx, fz_output);
217 out->state = state;
218 out->write = write;
219 out->close = close;
220 out->drop = drop;
221 if (bufsiz > 0)
222 {
223 out->bp = Memento_label(fz_malloc(ctx, bufsiz), "output_buf");
224 out->wp = out->bp;
225 out->ep = out->bp + bufsiz;
226 }
227 }
228 fz_catch(ctx)
229 {
230 if (drop)
231 drop(ctx, state);
232 fz_free(ctx, out);
233 fz_rethrow(ctx);
234 }
235 return out;
236 }
237
238 static void null_write(fz_context *ctx, void *opaque, const void *buffer, size_t count)
239 {
240 }
241
242 fz_output *
243 fz_new_output_with_path(fz_context *ctx, const char *filename, int append)
244 {
245 FILE *file;
246
247 if (filename == NULL)
248 fz_throw(ctx, FZ_ERROR_ARGUMENT, "no output to write to");
249
250 if (!strcmp(filename, "/dev/null"))
251 return fz_new_output(ctx, 0, NULL, null_write, NULL, NULL);
252 if (!strcmp(filename, "/dev/stdout"))
253 return fz_stdout(ctx);
254 if (!strcmp(filename, "/dev/stderr"))
255 return fz_stderr(ctx);
256
257 /* If <append> is false, we use fopen()'s 'x' flag to force an error if
258 * some other process creates the file immediately after we have removed
259 * it - this avoids vulnerability where a less-privilege process can create
260 * a link and get us to overwrite a different file. See:
261 * https://bugs.ghostscript.com/show_bug.cgi?id=701797
262 * http://www.open-std.org/jtc1/sc22//WG14/www/docs/n1339.pdf
263 */
264 #ifdef _WIN32
265 /* Ensure we create a brand new file. We don't want to clobber our old file. */
266 if (!append)
267 {
268 if (fz_remove_utf8(filename) < 0)
269 if (errno != ENOENT)
270 fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot remove file '%s': %s", filename, strerror(errno));
271 }
272 #if defined(__MINGW32__) || defined(__MINGW64__)
273 file = fz_fopen_utf8(filename, append ? "rb+" : "wb+"); /* 'x' flag not supported. */
274 #else
275 file = fz_fopen_utf8(filename, append ? "rb+" : "wb+x");
276 #endif
277 if (append)
278 {
279 if (file == NULL)
280 file = fz_fopen_utf8(filename, "wb+");
281 else
282 fseek(file, 0, SEEK_END);
283 }
284 #else
285 /* Ensure we create a brand new file. We don't want to clobber our old file. */
286 if (!append)
287 {
288 if (remove(filename) < 0)
289 if (errno != ENOENT)
290 fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot remove file '%s': %s", filename, strerror(errno));
291 }
292 file = fopen(filename, append ? "rb+" : "wb+x");
293 if (file == NULL && append)
294 file = fopen(filename, "wb+");
295 #endif
296 if (!file)
297 fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot open file '%s': %s", filename, strerror(errno));
298
299 return fz_new_output_with_file_ptr(ctx, file);
300 }
301
302 fz_output *
303 fz_new_output_with_file_ptr(fz_context *ctx, FILE *file)
304 {
305 fz_output *out;
306
307 if (!file)
308 return fz_new_output(ctx, 0, NULL, null_write, NULL, NULL);
309
310 setvbuf(file, NULL, _IONBF, 0); /* we do our own buffering */
311 out = fz_new_output(ctx, 8192, file, file_write, NULL, file_drop);
312 out->seek = file_seek;
313 out->tell = file_tell;
314 out->as_stream = file_as_stream;
315 out->truncate = file_truncate;
316
317 return out;
318 }
319
320 static void
321 buffer_write(fz_context *ctx, void *opaque, const void *data, size_t len)
322 {
323 fz_buffer *buffer = opaque;
324 fz_append_data(ctx, buffer, data, len);
325 }
326
327 static void
328 buffer_seek(fz_context *ctx, void *opaque, int64_t off, int whence)
329 {
330 fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot seek in buffer: %s", strerror(errno));
331 }
332
333 static int64_t
334 buffer_tell(fz_context *ctx, void *opaque)
335 {
336 fz_buffer *buffer = opaque;
337 return (int64_t)buffer->len;
338 }
339
340 static void
341 buffer_drop(fz_context *ctx, void *opaque)
342 {
343 fz_buffer *buffer = opaque;
344 fz_drop_buffer(ctx, buffer);
345 }
346
347 static void
348 buffer_reset(fz_context *ctx, void *opaque)
349 {
350 }
351
352 fz_output *
353 fz_new_output_with_buffer(fz_context *ctx, fz_buffer *buf)
354 {
355 fz_output *out = fz_new_output(ctx, 0, fz_keep_buffer(ctx, buf), buffer_write, NULL, buffer_drop);
356 out->seek = buffer_seek;
357 out->tell = buffer_tell;
358 out->reset = buffer_reset;
359 return out;
360 }
361
362 void
363 fz_close_output(fz_context *ctx, fz_output *out)
364 {
365 if (out == NULL)
366 return;
367 fz_flush_output(ctx, out);
368 if (!out->closed && out->close)
369 out->close(ctx, out->state);
370 out->closed = 1;
371 }
372
373 void
374 fz_drop_output(fz_context *ctx, fz_output *out)
375 {
376 if (out)
377 {
378 if (!out->closed)
379 fz_warn(ctx, "dropping unclosed output");
380 if (out->drop)
381 out->drop(ctx, out->state);
382 fz_free(ctx, out->bp);
383 if (out != &fz_stdout_global && out != &fz_stderr_global)
384 fz_free(ctx, out);
385 }
386 }
387
388 void
389 fz_reset_output(fz_context *ctx, fz_output *out)
390 {
391 if (!out)
392 return;
393 if (out->reset == NULL)
394 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Cannot reset this output");
395
396 out->reset(ctx, out->state);
397 out->closed = 0;
398 }
399
400 void
401 fz_seek_output(fz_context *ctx, fz_output *out, int64_t off, int whence)
402 {
403 if (out->seek == NULL)
404 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Cannot seek in unseekable output stream\n");
405 fz_flush_output(ctx, out);
406 out->seek(ctx, out->state, off, whence);
407 }
408
409 int64_t
410 fz_tell_output(fz_context *ctx, fz_output *out)
411 {
412 if (out->tell == NULL)
413 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Cannot tell in untellable output stream\n");
414 if (out->bp)
415 return out->tell(ctx, out->state) + (out->wp - out->bp);
416 return out->tell(ctx, out->state);
417 }
418
419 fz_stream *
420 fz_stream_from_output(fz_context *ctx, fz_output *out)
421 {
422 if (out->as_stream == NULL)
423 return NULL;
424 fz_flush_output(ctx, out);
425 return out->as_stream(ctx, out->state);
426 }
427
428 void
429 fz_truncate_output(fz_context *ctx, fz_output *out)
430 {
431 if (out->truncate == NULL)
432 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Cannot truncate this output stream");
433 fz_flush_output(ctx, out);
434 out->truncate(ctx, out->state);
435 }
436
437 static void
438 fz_write_emit(fz_context *ctx, void *out, int c)
439 {
440 fz_write_byte(ctx, out, c);
441 }
442
443 void
444 fz_write_vprintf(fz_context *ctx, fz_output *out, const char *fmt, va_list args)
445 {
446 fz_format_string(ctx, out, fz_write_emit, fmt, args);
447 }
448
449 void
450 fz_write_printf(fz_context *ctx, fz_output *out, const char *fmt, ...)
451 {
452 va_list args;
453 va_start(args, fmt);
454 fz_format_string(ctx, out, fz_write_emit, fmt, args);
455 va_end(args);
456 }
457
458 void
459 fz_flush_output(fz_context *ctx, fz_output *out)
460 {
461 fz_write_bits_sync(ctx, out);
462 if (out->wp > out->bp)
463 {
464 out->write(ctx, out->state, out->bp, out->wp - out->bp);
465 out->wp = out->bp;
466 }
467 }
468
469 void
470 fz_write_byte(fz_context *ctx, fz_output *out, unsigned char x)
471 {
472 if (out->bp)
473 {
474 if (out->wp == out->ep)
475 {
476 out->write(ctx, out->state, out->bp, out->wp - out->bp);
477 out->wp = out->bp;
478 }
479 *out->wp++ = x;
480 }
481 else
482 {
483 out->write(ctx, out->state, &x, 1);
484 }
485 }
486
487 void
488 fz_write_char(fz_context *ctx, fz_output *out, char x)
489 {
490 fz_write_byte(ctx, out, (unsigned char)x);
491 }
492
493 void
494 fz_write_data(fz_context *ctx, fz_output *out, const void *data_, size_t size)
495 {
496 const char *data = data_;
497
498 if (out->bp)
499 {
500 if (size >= (size_t) (out->ep - out->bp)) /* too large for buffer */
501 {
502 if (out->wp > out->bp)
503 {
504 out->write(ctx, out->state, out->bp, out->wp - out->bp);
505 out->wp = out->bp;
506 }
507 out->write(ctx, out->state, data, size);
508 }
509 else if (out->wp + size <= out->ep) /* fits in current buffer */
510 {
511 memcpy(out->wp, data, size);
512 out->wp += size;
513 }
514 else /* fits if we flush first */
515 {
516 size_t n = out->ep - out->wp;
517 memcpy(out->wp, data, n);
518 out->write(ctx, out->state, out->bp, out->ep - out->bp);
519 memcpy(out->bp, data + n, size - n);
520 out->wp = out->bp + size - n;
521 }
522 }
523 else
524 {
525 out->write(ctx, out->state, data, size);
526 }
527 }
528
529 void
530 fz_write_buffer(fz_context *ctx, fz_output *out, fz_buffer *buf)
531 {
532 fz_write_data(ctx, out, buf->data, buf->len);
533 }
534
535 void
536 fz_write_string(fz_context *ctx, fz_output *out, const char *s)
537 {
538 fz_write_data(ctx, out, s, strlen(s));
539 }
540
541 void
542 fz_write_int32_be(fz_context *ctx, fz_output *out, int x)
543 {
544 char data[4];
545
546 data[0] = x>>24;
547 data[1] = x>>16;
548 data[2] = x>>8;
549 data[3] = x;
550
551 fz_write_data(ctx, out, data, 4);
552 }
553
554 void
555 fz_write_uint32_be(fz_context *ctx, fz_output *out, unsigned int x)
556 {
557 fz_write_int32_be(ctx, out, (unsigned int)x);
558 }
559
560 void
561 fz_write_int32_le(fz_context *ctx, fz_output *out, int x)
562 {
563 char data[4];
564
565 data[0] = x;
566 data[1] = x>>8;
567 data[2] = x>>16;
568 data[3] = x>>24;
569
570 fz_write_data(ctx, out, data, 4);
571 }
572
573 void
574 fz_write_uint32_le(fz_context *ctx, fz_output *out, unsigned int x)
575 {
576 fz_write_int32_le(ctx, out, (int)x);
577 }
578
579 void
580 fz_write_int16_be(fz_context *ctx, fz_output *out, int x)
581 {
582 char data[2];
583
584 data[0] = x>>8;
585 data[1] = x;
586
587 fz_write_data(ctx, out, data, 2);
588 }
589
590 void
591 fz_write_uint16_be(fz_context *ctx, fz_output *out, unsigned int x)
592 {
593 fz_write_int16_be(ctx, out, (int)x);
594 }
595
596 void
597 fz_write_int16_le(fz_context *ctx, fz_output *out, int x)
598 {
599 char data[2];
600
601 data[0] = x;
602 data[1] = x>>8;
603
604 fz_write_data(ctx, out, data, 2);
605 }
606
607 void
608 fz_write_uint16_le(fz_context *ctx, fz_output *out, unsigned int x)
609 {
610 fz_write_int16_le(ctx, out, (int)x);
611 }
612
613 void
614 fz_write_float_le(fz_context *ctx, fz_output *out, float f)
615 {
616 union {float f; int32_t i;} u;
617 u.f = f;
618 fz_write_int32_le(ctx, out, u.i);
619 }
620
621 void
622 fz_write_float_be(fz_context *ctx, fz_output *out, float f)
623 {
624 union {float f; int32_t i;} u;
625 u.f = f;
626 fz_write_int32_be(ctx, out, u.i);
627 }
628
629 void
630 fz_write_rune(fz_context *ctx, fz_output *out, int rune)
631 {
632 char data[10];
633 fz_write_data(ctx, out, data, fz_runetochar(data, rune));
634 }
635
636 void
637 fz_write_base64(fz_context *ctx, fz_output *out, const unsigned char *data, size_t size, int newline)
638 {
639 static const char set[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
640 size_t i;
641 for (i = 0; i + 3 <= size; i += 3)
642 {
643 int c = data[i];
644 int d = data[i+1];
645 int e = data[i+2];
646 if (newline && (i & 15) == 0)
647 fz_write_byte(ctx, out, '\n');
648 fz_write_byte(ctx, out, set[c>>2]);
649 fz_write_byte(ctx, out, set[((c&3)<<4)|(d>>4)]);
650 fz_write_byte(ctx, out, set[((d&15)<<2)|(e>>6)]);
651 fz_write_byte(ctx, out, set[e&63]);
652 }
653 if (size - i == 2)
654 {
655 int c = data[i];
656 int d = data[i+1];
657 fz_write_byte(ctx, out, set[c>>2]);
658 fz_write_byte(ctx, out, set[((c&3)<<4)|(d>>4)]);
659 fz_write_byte(ctx, out, set[((d&15)<<2)]);
660 fz_write_byte(ctx, out, '=');
661 }
662 else if (size - i == 1)
663 {
664 int c = data[i];
665 fz_write_byte(ctx, out, set[c>>2]);
666 fz_write_byte(ctx, out, set[((c&3)<<4)]);
667 fz_write_byte(ctx, out, '=');
668 fz_write_byte(ctx, out, '=');
669 }
670 }
671
672 void
673 fz_write_base64_buffer(fz_context *ctx, fz_output *out, fz_buffer *buf, int newline)
674 {
675 unsigned char *data;
676 size_t size = fz_buffer_storage(ctx, buf, &data);
677 fz_write_base64(ctx, out, data, size, newline);
678 }
679
680 void
681 fz_append_base64(fz_context *ctx, fz_buffer *out, const unsigned char *data, size_t size, int newline)
682 {
683 static const char set[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
684 size_t i;
685 for (i = 0; i + 3 <= size; i += 3)
686 {
687 int c = data[i];
688 int d = data[i+1];
689 int e = data[i+2];
690 if (newline && (i & 15) == 0)
691 fz_append_byte(ctx, out, '\n');
692 fz_append_byte(ctx, out, set[c>>2]);
693 fz_append_byte(ctx, out, set[((c&3)<<4)|(d>>4)]);
694 fz_append_byte(ctx, out, set[((d&15)<<2)|(e>>6)]);
695 fz_append_byte(ctx, out, set[e&63]);
696 }
697 if (size - i == 2)
698 {
699 int c = data[i];
700 int d = data[i+1];
701 fz_append_byte(ctx, out, set[c>>2]);
702 fz_append_byte(ctx, out, set[((c&3)<<4)|(d>>4)]);
703 fz_append_byte(ctx, out, set[((d&15)<<2)]);
704 fz_append_byte(ctx, out, '=');
705 }
706 else if (size - i == 1)
707 {
708 int c = data[i];
709 fz_append_byte(ctx, out, set[c>>2]);
710 fz_append_byte(ctx, out, set[((c&3)<<4)]);
711 fz_append_byte(ctx, out, '=');
712 fz_append_byte(ctx, out, '=');
713 }
714 }
715
716 void
717 fz_append_base64_buffer(fz_context *ctx, fz_buffer *out, fz_buffer *buf, int newline)
718 {
719 unsigned char *data;
720 size_t size = fz_buffer_storage(ctx, buf, &data);
721 fz_append_base64(ctx, out, data, size, newline);
722 }
723
724
725 void
726 fz_save_buffer(fz_context *ctx, fz_buffer *buf, const char *filename)
727 {
728 fz_output *out = fz_new_output_with_path(ctx, filename, 0);
729 fz_try(ctx)
730 {
731 fz_write_data(ctx, out, buf->data, buf->len);
732 fz_close_output(ctx, out);
733 }
734 fz_always(ctx)
735 fz_drop_output(ctx, out);
736 fz_catch(ctx)
737 fz_rethrow(ctx);
738 }
739
740 fz_band_writer *fz_new_band_writer_of_size(fz_context *ctx, size_t size, fz_output *out)
741 {
742 fz_band_writer *writer = fz_calloc(ctx, size, 1);
743 writer->out = out;
744 return writer;
745 }
746
747 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)
748 {
749 if (writer == NULL || writer->band == NULL)
750 return;
751
752 if (w <= 0 || h <= 0 || n <= 0 || alpha < 0 || alpha > 1)
753 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Invalid bandwriter header dimensions/setup");
754
755 writer->w = w;
756 writer->h = h;
757 writer->s = fz_count_active_separations(ctx, seps);
758 writer->n = n;
759 writer->alpha = alpha;
760 writer->xres = xres;
761 writer->yres = yres;
762 writer->pagenum = pagenum;
763 writer->line = 0;
764 writer->seps = fz_keep_separations(ctx, seps);
765 writer->header(ctx, writer, cs);
766 }
767
768 void fz_write_band(fz_context *ctx, fz_band_writer *writer, int stride, int band_height, const unsigned char *samples)
769 {
770 if (writer == NULL || writer->band == NULL)
771 return;
772 if (writer->line + band_height > writer->h)
773 band_height = writer->h - writer->line;
774 if (band_height < 0) {
775 fz_throw(ctx, FZ_ERROR_LIMIT, "Too much band data!");
776 }
777 if (band_height > 0) {
778 writer->band(ctx, writer, stride, writer->line, band_height, samples);
779 writer->line += band_height;
780 }
781 if (writer->line == writer->h && writer->trailer) {
782 writer->trailer(ctx, writer);
783 /* Protect against more band_height == 0 calls */
784 writer->line++;
785 }
786 }
787
788 void fz_close_band_writer(fz_context *ctx, fz_band_writer *writer)
789 {
790 if (writer == NULL)
791 return;
792 if (writer->close != NULL)
793 writer->close(ctx, writer);
794 writer->close = NULL;
795 }
796
797 void fz_drop_band_writer(fz_context *ctx, fz_band_writer *writer)
798 {
799 if (writer == NULL)
800 return;
801 if (writer->drop != NULL)
802 writer->drop(ctx, writer);
803 fz_drop_separations(ctx, writer->seps);
804 fz_free(ctx, writer);
805 }
806
807 int fz_output_supports_stream(fz_context *ctx, fz_output *out)
808 {
809 return out != NULL && out->as_stream != NULL;
810 }
811
812 void fz_write_bits(fz_context *ctx, fz_output *out, unsigned int data, int num_bits)
813 {
814 while (num_bits)
815 {
816 /* How many bits will be left in the current byte after we
817 * insert these bits? */
818 int n = 8 - num_bits - out->buffered;
819 if (n >= 0)
820 {
821 /* We can fit our data in. */
822 out->bits |= data << n;
823 out->buffered += num_bits;
824 num_bits = 0;
825 }
826 else
827 {
828 /* There are 8 - out->buffered bits left to be filled. We have
829 * num_bits to fill it with, which is more, so we need to throw
830 * away the bottom 'num_bits - (8 - out->buffered)' bits. That's
831 * num_bits + out->buffered - 8 = -(8 - num_bits - out_buffered) = -n */
832 out->bits |= data >> -n;
833 data &= ~(out->bits << -n);
834 num_bits = -n;
835 out->buffered = 8;
836 }
837 if (out->buffered == 8)
838 {
839 fz_write_byte(ctx, out, out->bits);
840 out->buffered = 0;
841 out->bits = 0;
842 }
843 }
844
845 }
846
847 void fz_write_bits_sync(fz_context *ctx, fz_output *out)
848 {
849 if (out->buffered == 0)
850 return;
851 fz_write_bits(ctx, out, 0, 8 - out->buffered);
852 }
853
854 void
855 fz_write_stream(fz_context *ctx, fz_output *out, fz_stream *in)
856 {
857 size_t z;
858
859 while ((z = fz_available(ctx, in, 4096)) != 0)
860 {
861 fz_write_data(ctx, out, in->rp, z);
862 in->rp += z;
863 }
864 }