comparison mupdf-source/source/fitz/stream-open.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-2024 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 #ifdef _WIN32
35 #include <windows.h>
36 #include <wchar.h>
37 #else
38 #include <unistd.h>
39 #endif
40
41 int
42 fz_file_exists(fz_context *ctx, const char *path)
43 {
44 FILE *file;
45 #ifdef _WIN32
46 file = fz_fopen_utf8(path, "rb");
47 #else
48 file = fopen(path, "rb");
49 #endif
50 if (file)
51 fclose(file);
52 return !!file;
53 }
54
55 fz_stream *
56 fz_new_stream(fz_context *ctx, void *state, fz_stream_next_fn *next, fz_stream_drop_fn *drop)
57 {
58 fz_stream *stm = NULL;
59
60 fz_try(ctx)
61 {
62 stm = fz_malloc_struct(ctx, fz_stream);
63 }
64 fz_catch(ctx)
65 {
66 if (drop)
67 drop(ctx, state);
68 fz_rethrow(ctx);
69 }
70
71 stm->refs = 1;
72 stm->error = 0;
73 stm->eof = 0;
74 stm->pos = 0;
75
76 stm->bits = 0;
77 stm->avail = 0;
78
79 stm->rp = NULL;
80 stm->wp = NULL;
81
82 stm->state = state;
83 stm->next = next;
84 stm->drop = drop;
85 stm->seek = NULL;
86
87 return stm;
88 }
89
90 fz_stream *
91 fz_keep_stream(fz_context *ctx, fz_stream *stm)
92 {
93 return fz_keep_imp(ctx, stm, &stm->refs);
94 }
95
96 void
97 fz_drop_stream(fz_context *ctx, fz_stream *stm)
98 {
99 if (fz_drop_imp(ctx, stm, &stm->refs))
100 {
101 if (stm->drop)
102 stm->drop(ctx, stm->state);
103 fz_free(ctx, stm);
104 }
105 }
106
107 /* File stream */
108
109 // TODO: WIN32: HANDLE CreateFileW(), etc.
110 // TODO: POSIX: int creat(), read(), write(), lseeko, etc.
111
112 typedef struct
113 {
114 FILE *file;
115 char *filename;
116 #ifdef _WIN32
117 wchar_t *filename_w;
118 #endif
119 int del_on_drop;
120 unsigned char buffer[4096];
121 } fz_file_stream;
122
123 static int next_file(fz_context *ctx, fz_stream *stm, size_t n)
124 {
125 fz_file_stream *state = stm->state;
126
127 /* n is only a hint, that we can safely ignore */
128 n = fread(state->buffer, 1, sizeof(state->buffer), state->file);
129 if (n < sizeof(state->buffer) && ferror(state->file))
130 fz_throw(ctx, FZ_ERROR_SYSTEM, "read error: %s", strerror(errno));
131 stm->rp = state->buffer;
132 stm->wp = state->buffer + n;
133 stm->pos += (int64_t)n;
134
135 if (n == 0)
136 return EOF;
137 return *stm->rp++;
138 }
139
140 static void seek_file(fz_context *ctx, fz_stream *stm, int64_t offset, int whence)
141 {
142 fz_file_stream *state = stm->state;
143 #ifdef _WIN32
144 int64_t n = _fseeki64(state->file, offset, whence);
145 #else
146 int64_t n = fseeko(state->file, offset, whence);
147 #endif
148 if (n < 0)
149 fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot seek: %s", strerror(errno));
150 #ifdef _WIN32
151 stm->pos = _ftelli64(state->file);
152 #else
153 stm->pos = ftello(state->file);
154 #endif
155 stm->rp = state->buffer;
156 stm->wp = state->buffer;
157 }
158
159 static void drop_file(fz_context *ctx, void *state_)
160 {
161 fz_file_stream *state = state_;
162 if (state->filename && state->del_on_drop)
163 {
164 #ifdef _WIN32
165 if (state->filename_w)
166 _wunlink(state->filename_w);
167 else
168 #endif
169 unlink(state->filename);
170 }
171 #ifdef _WIN32
172 fz_free(ctx, state->filename_w);
173 #endif
174 fz_free(ctx, state->filename);
175 fz_free(ctx, state);
176 }
177
178 static void close_and_drop_file(fz_context *ctx, void *state_)
179 {
180 fz_file_stream *state = state_;
181 if (state)
182 {
183 int n = fclose(state->file);
184 if (n < 0)
185 fz_warn(ctx, "close error: %s", strerror(errno));
186 drop_file(ctx, state_);
187 }
188 }
189
190 static fz_stream *
191 fz_open_file_ptr(fz_context *ctx, FILE *file, const char *name, int wide, int del_on_drop)
192 {
193 fz_stream *stm;
194 fz_file_stream *state = NULL;
195
196 fz_var(state);
197
198 #ifndef _WIN32
199 assert(!wide);
200 #endif
201 fz_try(ctx)
202 {
203 state = fz_malloc_struct(ctx, fz_file_stream);
204 state->file = file;
205 #ifdef _WIN32
206 if (wide)
207 {
208 size_t z = wcslen((const wchar_t *)name)+1;
209 state->filename_w = fz_malloc(ctx, z*2);
210 memcpy(state->filename_w, name, z*2);
211 state->filename = fz_utf8_from_wchar(ctx, (const wchar_t *)name);
212 }
213 else
214 #endif
215 state->filename = fz_strdup(ctx, name);
216 state->del_on_drop = del_on_drop;
217
218 stm = fz_new_stream(ctx, state, next_file, close_and_drop_file);
219 stm->seek = seek_file;
220 }
221 fz_catch(ctx)
222 {
223 if (state == NULL && del_on_drop)
224 {
225 fclose(file);
226 #ifdef _WIN32
227 if (wide)
228 _wunlink((const wchar_t *)name);
229 else
230 #endif
231 unlink(name);
232 }
233 else
234 close_and_drop_file(ctx, state);
235 fz_rethrow(ctx);
236 }
237
238 return stm;
239 }
240
241 fz_stream *fz_open_file_ptr_no_close(fz_context *ctx, FILE *file)
242 {
243 fz_stream *stm;
244 fz_file_stream *state = fz_malloc_struct(ctx, fz_file_stream);
245 state->file = file;
246
247 /* We don't own the file ptr. Ensure we don't close it */
248 stm = fz_new_stream(ctx, state, next_file, drop_file);
249 stm->seek = seek_file;
250
251 return stm;
252 }
253
254 fz_stream *
255 fz_open_file(fz_context *ctx, const char *name)
256 {
257 FILE *file;
258 #ifdef _WIN32
259 file = fz_fopen_utf8(name, "rb");
260 #else
261 file = fopen(name, "rb");
262 #endif
263 if (file == NULL)
264 fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot open %s: %s", name, strerror(errno));
265 return fz_open_file_ptr(ctx, file, name, 0, 0);
266 }
267
268 fz_stream *
269 fz_open_file_autodelete(fz_context *ctx, const char *name)
270 {
271 FILE *file;
272 #ifdef _WIN32
273 file = fz_fopen_utf8(name, "rb");
274 #else
275 file = fopen(name, "rb");
276 #endif
277 if (file == NULL)
278 fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot open %s: %s", name, strerror(errno));
279 return fz_open_file_ptr(ctx, file, name, 0, 1);
280 }
281
282 fz_stream *
283 fz_try_open_file(fz_context *ctx, const char *name)
284 {
285 FILE *file;
286 #ifdef _WIN32
287 file = fz_fopen_utf8(name, "rb");
288 #else
289 file = fopen(name, "rb");
290 #endif
291 if (file == NULL)
292 return NULL;
293 return fz_open_file_ptr(ctx, file, name, 0, 0);
294 }
295
296 #ifdef _WIN32
297 fz_stream *
298 fz_open_file_w(fz_context *ctx, const wchar_t *name)
299 {
300 FILE *file = _wfopen(name, L"rb");
301 if (file == NULL)
302 fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot open file %ls: %s", name, strerror(errno));
303
304 return fz_open_file_ptr(ctx, file, (const char *)name, 1, 0);
305 }
306 #endif
307
308 const char *
309 fz_stream_filename(fz_context *ctx, fz_stream *stm)
310 {
311 if (!stm || stm->next != next_file)
312 return NULL;
313
314 return ((fz_file_stream *)stm->state)->filename;
315 }
316
317 /* Memory stream */
318
319 static int next_buffer(fz_context *ctx, fz_stream *stm, size_t max)
320 {
321 return EOF;
322 }
323
324 static void seek_buffer(fz_context *ctx, fz_stream *stm, int64_t offset, int whence)
325 {
326 int64_t pos = stm->pos - (stm->wp - stm->rp);
327 /* Convert to absolute pos */
328 if (whence == 1)
329 {
330 offset += pos; /* Was relative to current pos */
331 }
332 else if (whence == 2)
333 {
334 offset += stm->pos; /* Was relative to end */
335 }
336
337 if (offset < 0)
338 offset = 0;
339 if (offset > stm->pos)
340 offset = stm->pos;
341 stm->rp += (int)(offset - pos);
342 }
343
344 static void drop_buffer(fz_context *ctx, void *state_)
345 {
346 fz_buffer *state = (fz_buffer *)state_;
347 fz_drop_buffer(ctx, state);
348 }
349
350 fz_stream *
351 fz_open_buffer(fz_context *ctx, fz_buffer *buf)
352 {
353 fz_stream *stm;
354
355 if (buf == NULL)
356 return NULL;
357
358 fz_keep_buffer(ctx, buf);
359 stm = fz_new_stream(ctx, buf, next_buffer, drop_buffer);
360 stm->seek = seek_buffer;
361
362 stm->rp = buf->data;
363 stm->wp = buf->data + buf->len;
364
365 stm->pos = (int64_t)buf->len;
366
367 return stm;
368 }
369
370 fz_stream *
371 fz_open_memory(fz_context *ctx, const unsigned char *data, size_t len)
372 {
373 fz_stream *stm;
374
375 stm = fz_new_stream(ctx, NULL, next_buffer, NULL);
376 stm->seek = seek_buffer;
377
378 stm->rp = (unsigned char *)data;
379 stm->wp = (unsigned char *)data + len;
380
381 stm->pos = (int64_t)len;
382
383 return stm;
384 }