349 lines
12 KiB
HTML
349 lines
12 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>MuPDF I/O API</title>
|
|
<link rel="stylesheet" href="../style.css" type="text/css">
|
|
<style>
|
|
dl dt { font-family: monospace; margin-top: 0.5em; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<header>
|
|
<h1>MuPDF I/O API</h1>
|
|
</header>
|
|
|
|
<article>
|
|
|
|
<h2>Buffers</h2>
|
|
|
|
<p>
|
|
In order to represent a generic chunks of data we use the fz_buffer structure.
|
|
|
|
<pre>
|
|
typedef struct {
|
|
unsigned char *data;
|
|
size_t len; // current length
|
|
size_t cap; // total capacity
|
|
<i>reserved internal fields</i>
|
|
} fz_buffer;
|
|
|
|
fz_buffer *fz_keep_buffer(fz_context *ctx, fz_buffer *buf);
|
|
void fz_drop_buffer(fz_context *ctx, fz_buffer *buf);
|
|
</pre>
|
|
|
|
<p>
|
|
There are many ways to create a buffer. Some create a buffer shared immutable data,
|
|
others with data you can edit, and others by copying or decoding other data.
|
|
|
|
<dl>
|
|
<dt>fz_buffer *fz_new_buffer(fz_context *ctx, size_t capacity);
|
|
<dd>Create a new empty buffer, with the given initial capacity.
|
|
<dt>fz_buffer *fz_new_buffer_from_shared_data(fz_context *ctx, const unsigned char *data, size_t size);
|
|
<dd>Create a new buffer wrapping the given data pointer. The data is only referenced, and will not
|
|
be freed when the buffer is destroyed. The data pointer must NOT change or disappear while the buffer lives.
|
|
<dt>fz_buffer *fz_new_buffer_from_copied_data(fz_context *ctx, const unsigned char *data, size_t size);
|
|
<dd>Create a buffer containing a copy of the data pointed to.
|
|
<dt>fz_buffer *fz_new_buffer_from_base64(fz_context *ctx, const char *data, size_t size);
|
|
<dd>Create a buffer containing the decoded BASE64 data.
|
|
</dl>
|
|
|
|
<p>
|
|
Sometimes you want to create buffers piece by piece by appending strings or other data to it,
|
|
while dynamically growing the underlying storage.
|
|
|
|
<pre>
|
|
void fz_append_data(fz_context *ctx, fz_buffer *buf, const void *data, size_t len);
|
|
void fz_append_string(fz_context *ctx, fz_buffer *buf, const char *string);
|
|
void fz_append_byte(fz_context *ctx, fz_buffer *buf, int byte);
|
|
void fz_append_rune(fz_context *ctx, fz_buffer *buf, int rune);
|
|
void fz_append_int16_be(fz_context *ctx, fz_buffer *buf, int x);
|
|
void fz_append_int16_le(fz_context *ctx, fz_buffer *buf, int x);
|
|
void fz_append_int32_be(fz_context *ctx, fz_buffer *buf, int x);
|
|
void fz_append_int32_le(fz_context *ctx, fz_buffer *buf, int x);
|
|
void fz_append_printf(fz_context *ctx, fz_buffer *buffer, const char *fmt, ...);
|
|
void fz_append_vprintf(fz_context *ctx, fz_buffer *buffer, const char *fmt, va_list args);
|
|
</pre>
|
|
|
|
<p>
|
|
You can also write a bit stream with the following functions.
|
|
The buffer length always covers all the bits in the buffer, including
|
|
any unused ones in the last byte, which will always be zero.
|
|
|
|
<dl>
|
|
<dt>void fz_append_bits(fz_context *ctx, fz_buffer *buf, int value, int count);
|
|
<dd>Write the lower count bits from value into the buffer.
|
|
<dt>void fz_append_bits_pad(fz_context *ctx, fz_buffer *buf);
|
|
<dd>Write enough zero bits to be byte aligned.
|
|
</dl>
|
|
|
|
<p>
|
|
You can use the buffer data as a zero-terminated C string by calling the following function.
|
|
This will ensure that there is a zero terminator after the last byte and return
|
|
a pointer to the first byte. This pointer is only borrowed, and should only be used
|
|
briefly, before the buffer is changed again (which may reallocate or free the data).
|
|
|
|
<pre>
|
|
const char *fz_string_from_buffer(fz_context *ctx, fz_buffer *buf);
|
|
</pre>
|
|
|
|
<p>
|
|
You can also read and write the contents of a buffer to file.
|
|
|
|
<dl>
|
|
<dt>fz_buffer *fz_read_file(fz_context *ctx, const char *filename);
|
|
<dd>Read the contents of a file into a buffer.
|
|
<dt>void fz_save_buffer(fz_context *ctx, fz_buffer *buf, const char *filename);
|
|
<dd>Save the contents of a buffer to a file.
|
|
</dl>
|
|
|
|
<h2>Input Streams and Filters</h2>
|
|
|
|
<p>
|
|
An input stream reads data from a source. Some stream types can decompress and decrypt data,
|
|
and these streams can be chained together in a pipeline.
|
|
|
|
<pre>
|
|
typedef struct { <i>internal</i> } fz_stream;
|
|
|
|
fz_stream *fz_keep_stream(fz_context *ctx, fz_stream *stm);
|
|
void fz_drop_stream(fz_context *ctx, fz_stream *stm);
|
|
</pre>
|
|
|
|
<dl>
|
|
<dt>fz_stream *fz_open_file(fz_context *ctx, const char *filename);
|
|
<dd>Open a stream reading the contents of a file.
|
|
<dt>fz_stream *fz_open_memory(fz_context *ctx, const unsigned char *data, size_t len);
|
|
<dd>Open a stream reading from the data pointer.
|
|
<dt>fz_stream *fz_open_buffer(fz_context *ctx, fz_buffer *buf);
|
|
<dd>Open a stream reading from a buffer.
|
|
</dl>
|
|
|
|
<p>
|
|
The basic stream operations you expect are available.
|
|
|
|
<pre>
|
|
int64_t fz_tell(fz_context *ctx, fz_stream *stm);
|
|
void fz_seek(fz_context *ctx, fz_stream *stm, int64_t offset, int whence);
|
|
size_t fz_read(fz_context *ctx, fz_stream *stm, unsigned char *data, size_t len);
|
|
size_t fz_skip(fz_context *ctx, fz_stream *stm, size_t len);
|
|
</pre>
|
|
|
|
<dl>
|
|
<dt>fz_buffer *fz_read_all(fz_context *ctx, fz_stream *stm, size_t initial);
|
|
<dd>Read the remaining data into a new buffer.
|
|
|
|
<dt>char *fz_read_line(fz_context *ctx, fz_stream *stm, char *buf, size_t n);
|
|
<dd>Behaves like fgets().
|
|
</dl>
|
|
|
|
<pre>
|
|
int fz_read_byte(fz_context *ctx, fz_stream *stm);
|
|
int fz_peek_byte(fz_context *ctx, fz_stream *stm);
|
|
int fz_is_eof(fz_context *ctx, fz_stream *stm);
|
|
</pre>
|
|
|
|
<p>
|
|
You can read binary data one integer at a time. The default is big endian, but LE versions are also
|
|
provided.
|
|
|
|
<pre>
|
|
uint16_t fz_read_uint16(fz_context *ctx, fz_stream *stm);
|
|
uint32_t fz_read_uint24(fz_context *ctx, fz_stream *stm);
|
|
uint32_t fz_read_uint32(fz_context *ctx, fz_stream *stm);
|
|
uint64_t fz_read_uint64(fz_context *ctx, fz_stream *stm);
|
|
|
|
uint16_t fz_read_uint16_le(fz_context *ctx, fz_stream *stm);
|
|
uint32_t fz_read_uint24_le(fz_context *ctx, fz_stream *stm);
|
|
uint32_t fz_read_uint32_le(fz_context *ctx, fz_stream *stm);
|
|
uint64_t fz_read_uint64_le(fz_context *ctx, fz_stream *stm);
|
|
|
|
int16_t fz_read_int16(fz_context *ctx, fz_stream *stm);
|
|
int32_t fz_read_int32(fz_context *ctx, fz_stream *stm);
|
|
int64_t fz_read_int64(fz_context *ctx, fz_stream *stm);
|
|
|
|
int16_t fz_read_int16_le(fz_context *ctx, fz_stream *stm);
|
|
int32_t fz_read_int32_le(fz_context *ctx, fz_stream *stm);
|
|
int64_t fz_read_int64_le(fz_context *ctx, fz_stream *stm);
|
|
</pre>
|
|
|
|
<p>
|
|
Reading bit streams is also possible:
|
|
|
|
<pre>
|
|
unsigned int fz_read_bits(fz_context *ctx, fz_stream *stm, int n);
|
|
unsigned int fz_read_rbits(fz_context *ctx, fz_stream *stm, int n);
|
|
void fz_sync_bits(fz_context *ctx, fz_stream *stm);
|
|
int fz_is_eof_bits(fz_context *ctx, fz_stream *stm);
|
|
</pre>
|
|
|
|
<p>
|
|
Various decoding, decompression, and decryption filters can be chained together.
|
|
|
|
<pre>
|
|
fz_stream *fz_open_null_filter(fz_context *ctx, fz_stream *chain, int len, int64_t offset);
|
|
fz_stream *fz_open_arc4(fz_context *ctx, fz_stream *chain, unsigned char *key, unsigned keylen);
|
|
fz_stream *fz_open_aesd(fz_context *ctx, fz_stream *chain, unsigned char *key, unsigned keylen);
|
|
fz_stream *fz_open_a85d(fz_context *ctx, fz_stream *chain);
|
|
fz_stream *fz_open_ahxd(fz_context *ctx, fz_stream *chain);
|
|
fz_stream *fz_open_rld(fz_context *ctx, fz_stream *chain);
|
|
fz_stream *fz_open_flated(fz_context *ctx, fz_stream *chain, int window_bits);
|
|
|
|
fz_stream *fz_open_dctd(fz_context *ctx, fz_stream *chain,
|
|
int color_transform,
|
|
int l2factor,
|
|
fz_stream *jpegtables);
|
|
|
|
fz_stream *fz_open_faxd(fz_context *ctx, fz_stream *chain,
|
|
int k,
|
|
int end_of_line,
|
|
int encoded_byte_align,
|
|
int columns,
|
|
int rows,
|
|
int end_of_block,
|
|
int black_is_1);
|
|
|
|
fz_stream *fz_open_lzwd(fz_context *ctx, fz_stream *chain,
|
|
int early_change,
|
|
int min_bits,
|
|
int reverse_bits,
|
|
int old_tiff);
|
|
|
|
fz_stream *fz_open_predict(fz_context *ctx, fz_stream *chain,
|
|
int predictor,
|
|
int columns,
|
|
int colors,
|
|
int bpc);
|
|
</pre>
|
|
|
|
<h2>Output Streams and Filters</h2>
|
|
|
|
<p>
|
|
Output streams let us write data to a sink, usually a file on disk or a buffer.
|
|
As with the input streams, output streams can be chained together to compress,
|
|
encrypt, and encode data.
|
|
|
|
<pre>
|
|
typedef struct { <i>internal</i> } fz_output;
|
|
</pre>
|
|
|
|
<p>
|
|
Because output may be buffered in the writer, we need a separate
|
|
close function to ensure that an output stream is properly flushed
|
|
and any end of data markers are written. This is separate to the
|
|
drop function, which just frees data. If a writing operation has
|
|
succeeded, you need to call close on the output stream before
|
|
dropping it.
|
|
If you encounter an error while writing data, you can just drop the stream directly, since
|
|
we couldn't finish writing it and closing it properly would be irrelevant.
|
|
|
|
<pre>
|
|
void fz_close_output(fz_context *ctx, fz_output *out);
|
|
void fz_drop_output(fz_context *ctx, fz_output *out);
|
|
</pre>
|
|
|
|
<p>
|
|
Outputs can be created to write to files or buffers.
|
|
You can also implement your own data sink by providing a state pointer
|
|
and callback functions.
|
|
|
|
<pre>
|
|
fz_output *fz_new_output_with_path(fz_context *, const char *filename, int append);
|
|
fz_output *fz_new_output_with_buffer(fz_context *ctx, fz_buffer *buf);
|
|
|
|
fz_output *fz_new_output(fz_context *ctx,
|
|
int buffer_size,
|
|
void *state,
|
|
void (*write)(fz_context *ctx, void *state, const void *data, size_t n),
|
|
void (*close)(fz_context *ctx, void *state),
|
|
void (*drop)(fz_context *ctx, void *state));
|
|
</pre>
|
|
|
|
<p>
|
|
The usual suspects are available, as well as functions to write
|
|
integers of various sizes and byte orders.
|
|
|
|
<dl>
|
|
<dt>void fz_seek_output(fz_context *ctx, fz_output *out, int64_t off, int whence);
|
|
<dd>Seek to a location in the output. This is not available for all output types.
|
|
<dt>int64_t fz_tell_output(fz_context *ctx, fz_output *out);
|
|
<dd>Tell the current write location of the output stream.
|
|
</dl>
|
|
|
|
<pre>
|
|
void fz_write_data(fz_context *ctx, fz_output *out, const void *data, size_t size);
|
|
void fz_write_string(fz_context *ctx, fz_output *out, const char *s);
|
|
void fz_write_byte(fz_context *ctx, fz_output *out, unsigned char x);
|
|
void fz_write_rune(fz_context *ctx, fz_output *out, int rune);
|
|
void fz_write_int16_be(fz_context *ctx, fz_output *out, int x);
|
|
void fz_write_int16_le(fz_context *ctx, fz_output *out, int x);
|
|
void fz_write_int32_be(fz_context *ctx, fz_output *out, int x);
|
|
void fz_write_int32_le(fz_context *ctx, fz_output *out, int x);
|
|
void fz_write_printf(fz_context *ctx, fz_output *out, const char *fmt, ...);
|
|
void fz_write_vprintf(fz_context *ctx, fz_output *out, const char *fmt, va_list ap);
|
|
void fz_write_base64(fz_context *ctx, fz_output *out, const unsigned char *data, int size, int newline);
|
|
</pre>
|
|
|
|
<p>
|
|
Output streams can be chained together to add encryption, compression, and
|
|
encoding. Note that these do not take ownership of the chained stream, they
|
|
only write to it. For example, you can write a header, create a compression
|
|
filter stream, write some data to the filter to compress the data, close the
|
|
filter and then keep writing more data to the original stream.
|
|
|
|
<pre>
|
|
fz_output *fz_new_arc4_output(fz_context *ctx, fz_output *chain, unsigned char *key, size_t keylen);
|
|
fz_output *fz_new_ascii85_output(fz_context *ctx, fz_output *chain);
|
|
fz_output *fz_new_asciihex_output(fz_context *ctx, fz_output *chain);
|
|
fz_output *fz_new_deflate_output(fz_context *ctx, fz_output *chain, int effort, int no_header);
|
|
fz_output *fz_new_rle_output(fz_context *ctx, fz_output *chain);
|
|
</pre>
|
|
|
|
<h2>File Archives</h2>
|
|
|
|
<p>
|
|
The archive structure is a read-only collection of files. This is typically a
|
|
Zip file or directory on disk, but other formats are also supported.
|
|
|
|
<pre>
|
|
typedef struct { <i>internal</i> } fz_archive;
|
|
|
|
void fz_drop_archive(fz_context *ctx, fz_archive *arch);
|
|
|
|
int fz_is_directory(fz_context *ctx, const char *path);
|
|
|
|
fz_archive *fz_open_directory(fz_context *ctx, const char *path);
|
|
fz_archive *fz_open_archive(fz_context *ctx, const char *filename);
|
|
fz_archive *fz_open_archive_with_stream(fz_context *ctx, fz_stream *file);
|
|
|
|
int fz_count_archive_entries(fz_context *ctx, fz_archive *arch);
|
|
const char *fz_list_archive_entry(fz_context *ctx, fz_archive *arch, int idx);
|
|
|
|
int fz_has_archive_entry(fz_context *ctx, fz_archive *arch, const char *name);
|
|
fz_stream *fz_open_archive_entry(fz_context *ctx, fz_archive *arch, const char *name);
|
|
fz_buffer *fz_read_archive_entry(fz_context *ctx, fz_archive *arch, const char *name);
|
|
</pre>
|
|
|
|
<p>
|
|
We can also create new Zip archives.
|
|
|
|
<pre>
|
|
typedef struct { <i>internal</i> } fz_zip_writer;
|
|
|
|
fz_zip_writer *fz_new_zip_writer(fz_context *ctx, const char *filename);
|
|
fz_zip_writer *fz_new_zip_writer_with_output(fz_context *ctx, fz_output *out);
|
|
void fz_write_zip_entry(fz_context *ctx, fz_zip_writer *zip, const char *name, fz_buffer *buf, int compress);
|
|
void fz_close_zip_writer(fz_context *ctx, fz_zip_writer *zip);
|
|
void fz_drop_zip_writer(fz_context *ctx, fz_zip_writer *zip);
|
|
</pre>
|
|
|
|
</article>
|
|
|
|
<footer>
|
|
<a href="https://www.artifex.com/"><img src="../artifex-logo.png" align="right"></a>
|
|
Copyright © 2019 Artifex Software Inc.
|
|
</footer>
|
|
|
|
</body>
|
|
</html>
|