eBookReaderSwitch/mupdf/source/fitz/stream-open.c

303 lines
6.4 KiB
C

#define _LARGEFILE_SOURCE
#ifndef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 64
#endif
#include "mupdf/fitz.h"
#include "fitz-imp.h"
#include <string.h>
#include <errno.h>
#include <stdio.h>
/*
Return true if the named file exists and is readable.
*/
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;
}
/*
Create a new stream object with the given
internal state and function pointers.
state: Internal state (opaque to everything but implementation).
next: Should provide the next set of bytes (up to max) of stream
data. Return the number of bytes read, or EOF when there is no
more data.
drop: Should clean up and free the internal state. May not
throw exceptions.
*/
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 fz_file_stream_s
{
FILE *file;
unsigned char buffer[1048576];
} 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_GENERIC, "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;
/* Purges the file to see if we can get rid of inconsistencies */
fpurge(state->file);
#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_GENERIC, "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_;
int n = fclose(state->file);
if (n < 0)
fz_warn(ctx, "close error: %s", strerror(errno));
fz_free(ctx, state);
}
static fz_stream *
fz_open_file_ptr(fz_context *ctx, FILE *file)
{
fz_stream *stm;
fz_file_stream *state = fz_malloc_struct(ctx, fz_file_stream);
state->file = file;
stm = fz_new_stream(ctx, state, next_file, drop_file);
stm->seek = seek_file;
return stm;
}
fz_stream *fz_open_file_ptr_no_close(fz_context *ctx, FILE *file)
{
fz_stream *stm = fz_open_file_ptr(ctx, file);
/* We don't own the file ptr. Ensure we don't close it */
stm->drop = fz_free;
return stm;
}
/*
Open the named file and wrap it in a stream.
filename: Path to a file. On non-Windows machines the filename should
be exactly as it would be passed to fopen(2). On Windows machines, the
path should be UTF-8 encoded so that non-ASCII characters can be
represented. Other platforms do the encoding as standard anyway (and
in most cases, particularly for MacOS and Linux, the encoding they
use is UTF-8 anyway).
*/
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_GENERIC, "cannot open %s: %s", name, strerror(errno));
return fz_open_file_ptr(ctx, file);
}
#ifdef _WIN32
/*
Open the named file and wrap it in a stream.
This function is only available when compiling for Win32.
filename: Wide character path to the file as it would be given
to _wfopen().
*/
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_GENERIC, "cannot open file %ls: %s", name, strerror(errno));
return fz_open_file_ptr(ctx, file);
}
#endif
/* 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);
}
/*
Open a buffer as a stream.
buf: The buffer to open. Ownership of the buffer is NOT passed in
(this function takes its own reference).
Returns pointer to newly created stream. May throw exceptions on
failure to allocate.
*/
fz_stream *
fz_open_buffer(fz_context *ctx, fz_buffer *buf)
{
fz_stream *stm;
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;
}
/*
Open a block of memory as a stream.
data: Pointer to start of data block. Ownership of the data block is
NOT passed in.
len: Number of bytes in data block.
Returns pointer to newly created stream. May throw exceptions on
failure to allocate.
*/
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;
}