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