1 #define _LARGEFILE_SOURCE
2 #ifndef _FILE_OFFSET_BITS
3 #define _FILE_OFFSET_BITS 64
4 #endif
5 
6 #include "mupdf/fitz.h"
7 
8 #include <string.h>
9 #include <errno.h>
10 #include <stdio.h>
11 
12 int
fz_file_exists(fz_context * ctx,const char * path)13 fz_file_exists(fz_context *ctx, const char *path)
14 {
15 	FILE *file;
16 #ifdef _WIN32
17 	file = fz_fopen_utf8(path, "rb");
18 #else
19 	file = fopen(path, "rb");
20 #endif
21 	if (file)
22 		fclose(file);
23 	return !!file;
24 }
25 
26 fz_stream *
fz_new_stream(fz_context * ctx,void * state,fz_stream_next_fn * next,fz_stream_drop_fn * drop)27 fz_new_stream(fz_context *ctx, void *state, fz_stream_next_fn *next, fz_stream_drop_fn *drop)
28 {
29 	fz_stream *stm = NULL;
30 
31 	fz_try(ctx)
32 	{
33 		stm = fz_malloc_struct(ctx, fz_stream);
34 	}
35 	fz_catch(ctx)
36 	{
37 		if (drop)
38 			drop(ctx, state);
39 		fz_rethrow(ctx);
40 	}
41 
42 	stm->refs = 1;
43 	stm->error = 0;
44 	stm->eof = 0;
45 	stm->pos = 0;
46 
47 	stm->bits = 0;
48 	stm->avail = 0;
49 
50 	stm->rp = NULL;
51 	stm->wp = NULL;
52 
53 	stm->state = state;
54 	stm->next = next;
55 	stm->drop = drop;
56 	stm->seek = NULL;
57 
58 	return stm;
59 }
60 
61 fz_stream *
fz_keep_stream(fz_context * ctx,fz_stream * stm)62 fz_keep_stream(fz_context *ctx, fz_stream *stm)
63 {
64 	return fz_keep_imp(ctx, stm, &stm->refs);
65 }
66 
67 void
fz_drop_stream(fz_context * ctx,fz_stream * stm)68 fz_drop_stream(fz_context *ctx, fz_stream *stm)
69 {
70 	if (fz_drop_imp(ctx, stm, &stm->refs))
71 	{
72 		if (stm->drop)
73 			stm->drop(ctx, stm->state);
74 		fz_free(ctx, stm);
75 	}
76 }
77 
78 /* File stream */
79 
80 // TODO: WIN32: HANDLE CreateFileW(), etc.
81 // TODO: POSIX: int creat(), read(), write(), lseeko, etc.
82 
83 typedef struct
84 {
85 	FILE *file;
86 	unsigned char buffer[4096];
87 } fz_file_stream;
88 
next_file(fz_context * ctx,fz_stream * stm,size_t n)89 static int next_file(fz_context *ctx, fz_stream *stm, size_t n)
90 {
91 	fz_file_stream *state = stm->state;
92 
93 	/* n is only a hint, that we can safely ignore */
94 	n = fread(state->buffer, 1, sizeof(state->buffer), state->file);
95 	if (n < sizeof(state->buffer) && ferror(state->file))
96 		fz_throw(ctx, FZ_ERROR_GENERIC, "read error: %s", strerror(errno));
97 	stm->rp = state->buffer;
98 	stm->wp = state->buffer + n;
99 	stm->pos += (int64_t)n;
100 
101 	if (n == 0)
102 		return EOF;
103 	return *stm->rp++;
104 }
105 
seek_file(fz_context * ctx,fz_stream * stm,int64_t offset,int whence)106 static void seek_file(fz_context *ctx, fz_stream *stm, int64_t offset, int whence)
107 {
108 	fz_file_stream *state = stm->state;
109 #ifdef _WIN32
110 	int64_t n = _fseeki64(state->file, offset, whence);
111 #else
112 	int64_t n = fseeko(state->file, offset, whence);
113 #endif
114 	if (n < 0)
115 		fz_throw(ctx, FZ_ERROR_GENERIC, "cannot seek: %s", strerror(errno));
116 #ifdef _WIN32
117 	stm->pos = _ftelli64(state->file);
118 #else
119 	stm->pos = ftello(state->file);
120 #endif
121 	stm->rp = state->buffer;
122 	stm->wp = state->buffer;
123 }
124 
drop_file(fz_context * ctx,void * state_)125 static void drop_file(fz_context *ctx, void *state_)
126 {
127 	fz_file_stream *state = state_;
128 	int n = fclose(state->file);
129 	if (n < 0)
130 		fz_warn(ctx, "close error: %s", strerror(errno));
131 	fz_free(ctx, state);
132 }
133 
134 static fz_stream *
fz_open_file_ptr(fz_context * ctx,FILE * file)135 fz_open_file_ptr(fz_context *ctx, FILE *file)
136 {
137 	fz_stream *stm;
138 	fz_file_stream *state = fz_malloc_struct(ctx, fz_file_stream);
139 	state->file = file;
140 
141 	stm = fz_new_stream(ctx, state, next_file, drop_file);
142 	stm->seek = seek_file;
143 
144 	return stm;
145 }
146 
fz_open_file_ptr_no_close(fz_context * ctx,FILE * file)147 fz_stream *fz_open_file_ptr_no_close(fz_context *ctx, FILE *file)
148 {
149 	fz_stream *stm = fz_open_file_ptr(ctx, file);
150 	/* We don't own the file ptr. Ensure we don't close it */
151 	stm->drop = fz_free;
152 	return stm;
153 }
154 
155 fz_stream *
fz_open_file(fz_context * ctx,const char * name)156 fz_open_file(fz_context *ctx, const char *name)
157 {
158 	FILE *file;
159 #ifdef _WIN32
160 	file = fz_fopen_utf8(name, "rb");
161 #else
162 	file = fopen(name, "rb");
163 #endif
164 	if (file == NULL)
165 		fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open %s: %s", name, strerror(errno));
166 	return fz_open_file_ptr(ctx, file);
167 }
168 
169 #ifdef _WIN32
170 fz_stream *
fz_open_file_w(fz_context * ctx,const wchar_t * name)171 fz_open_file_w(fz_context *ctx, const wchar_t *name)
172 {
173 	FILE *file = _wfopen(name, L"rb");
174 	if (file == NULL)
175 		fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open file %ls: %s", name, strerror(errno));
176 	return fz_open_file_ptr(ctx, file);
177 }
178 #endif
179 
180 /* Memory stream */
181 
next_buffer(fz_context * ctx,fz_stream * stm,size_t max)182 static int next_buffer(fz_context *ctx, fz_stream *stm, size_t max)
183 {
184 	return EOF;
185 }
186 
seek_buffer(fz_context * ctx,fz_stream * stm,int64_t offset,int whence)187 static void seek_buffer(fz_context *ctx, fz_stream *stm, int64_t offset, int whence)
188 {
189 	int64_t pos = stm->pos - (stm->wp - stm->rp);
190 	/* Convert to absolute pos */
191 	if (whence == 1)
192 	{
193 		offset += pos; /* Was relative to current pos */
194 	}
195 	else if (whence == 2)
196 	{
197 		offset += stm->pos; /* Was relative to end */
198 	}
199 
200 	if (offset < 0)
201 		offset = 0;
202 	if (offset > stm->pos)
203 		offset = stm->pos;
204 	stm->rp += (int)(offset - pos);
205 }
206 
drop_buffer(fz_context * ctx,void * state_)207 static void drop_buffer(fz_context *ctx, void *state_)
208 {
209 	fz_buffer *state = (fz_buffer *)state_;
210 	fz_drop_buffer(ctx, state);
211 }
212 
213 fz_stream *
fz_open_buffer(fz_context * ctx,fz_buffer * buf)214 fz_open_buffer(fz_context *ctx, fz_buffer *buf)
215 {
216 	fz_stream *stm;
217 
218 	fz_keep_buffer(ctx, buf);
219 	stm = fz_new_stream(ctx, buf, next_buffer, drop_buffer);
220 	stm->seek = seek_buffer;
221 
222 	stm->rp = buf->data;
223 	stm->wp = buf->data + buf->len;
224 
225 	stm->pos = (int64_t)buf->len;
226 
227 	return stm;
228 }
229 
230 fz_stream *
fz_open_memory(fz_context * ctx,const unsigned char * data,size_t len)231 fz_open_memory(fz_context *ctx, const unsigned char *data, size_t len)
232 {
233 	fz_stream *stm;
234 
235 	stm = fz_new_stream(ctx, NULL, next_buffer, NULL);
236 	stm->seek = seek_buffer;
237 
238 	stm->rp = (unsigned char *)data;
239 	stm->wp = (unsigned char *)data + len;
240 
241 	stm->pos = (int64_t)len;
242 
243 	return stm;
244 }
245