Coverage Report

Created: 2025-01-28 06:17

/src/mupdf/source/fitz/stream-open.c
Line
Count
Source (jump to first uncovered line)
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
0
{
44
0
  FILE *file;
45
#ifdef _WIN32
46
  file = fz_fopen_utf8(path, "rb");
47
#else
48
0
  file = fopen(path, "rb");
49
0
#endif
50
0
  if (file)
51
0
    fclose(file);
52
0
  return !!file;
53
0
}
54
55
fz_stream *
56
fz_new_stream(fz_context *ctx, void *state, fz_stream_next_fn *next, fz_stream_drop_fn *drop)
57
815k
{
58
815k
  fz_stream *stm = NULL;
59
60
1.63M
  fz_try(ctx)
61
1.63M
  {
62
815k
    stm = fz_malloc_struct(ctx, fz_stream);
63
815k
  }
64
1.63M
  fz_catch(ctx)
65
0
  {
66
0
    if (drop)
67
0
      drop(ctx, state);
68
0
    fz_rethrow(ctx);
69
0
  }
70
71
815k
  stm->refs = 1;
72
815k
  stm->error = 0;
73
815k
  stm->eof = 0;
74
815k
  stm->pos = 0;
75
76
815k
  stm->bits = 0;
77
815k
  stm->avail = 0;
78
79
815k
  stm->rp = NULL;
80
815k
  stm->wp = NULL;
81
82
815k
  stm->state = state;
83
815k
  stm->next = next;
84
815k
  stm->drop = drop;
85
815k
  stm->seek = NULL;
86
87
815k
  return stm;
88
815k
}
89
90
fz_stream *
91
fz_keep_stream(fz_context *ctx, fz_stream *stm)
92
777k
{
93
777k
  return fz_keep_imp(ctx, stm, &stm->refs);
94
777k
}
95
96
void
97
fz_drop_stream(fz_context *ctx, fz_stream *stm)
98
1.93M
{
99
1.93M
  if (fz_drop_imp(ctx, stm, &stm->refs))
100
815k
  {
101
815k
    if (stm->drop)
102
799k
      stm->drop(ctx, stm->state);
103
815k
    fz_free(ctx, stm);
104
815k
  }
105
1.93M
}
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
0
{
125
0
  fz_file_stream *state = stm->state;
126
127
  /* n is only a hint, that we can safely ignore */
128
0
  n = fread(state->buffer, 1, sizeof(state->buffer), state->file);
129
0
  if (n < sizeof(state->buffer) && ferror(state->file))
130
0
    fz_throw(ctx, FZ_ERROR_SYSTEM, "read error: %s", strerror(errno));
131
0
  stm->rp = state->buffer;
132
0
  stm->wp = state->buffer + n;
133
0
  stm->pos += (int64_t)n;
134
135
0
  if (n == 0)
136
0
    return EOF;
137
0
  return *stm->rp++;
138
0
}
139
140
static void seek_file(fz_context *ctx, fz_stream *stm, int64_t offset, int whence)
141
0
{
142
0
  fz_file_stream *state = stm->state;
143
#ifdef _WIN32
144
  int64_t n = _fseeki64(state->file, offset, whence);
145
#else
146
0
  int64_t n = fseeko(state->file, offset, whence);
147
0
#endif
148
0
  if (n < 0)
149
0
    fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot seek: %s", strerror(errno));
150
#ifdef _WIN32
151
  stm->pos = _ftelli64(state->file);
152
#else
153
0
  stm->pos = ftello(state->file);
154
0
#endif
155
0
  stm->rp = state->buffer;
156
0
  stm->wp = state->buffer;
157
0
}
158
159
static void drop_file(fz_context *ctx, void *state_)
160
0
{
161
0
  fz_file_stream *state = state_;
162
0
  if (state->filename && state->del_on_drop)
163
0
  {
164
#ifdef _WIN32
165
    if (state->filename_w)
166
      _wunlink(state->filename_w);
167
    else
168
#endif
169
0
    unlink(state->filename);
170
0
  }
171
#ifdef _WIN32
172
  fz_free(ctx, state->filename_w);
173
#endif
174
0
  fz_free(ctx, state->filename);
175
0
  fz_free(ctx, state);
176
0
}
177
178
static void close_and_drop_file(fz_context *ctx, void *state_)
179
0
{
180
0
  fz_file_stream *state = state_;
181
0
  if (state)
182
0
  {
183
0
    int n = fclose(state->file);
184
0
    if (n < 0)
185
0
      fz_warn(ctx, "close error: %s", strerror(errno));
186
0
    drop_file(ctx, state_);
187
0
  }
188
0
}
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
0
{
193
0
  fz_stream *stm;
194
0
  fz_file_stream *state = NULL;
195
196
0
  fz_var(state);
197
198
0
#ifndef _WIN32
199
0
  assert(!wide);
200
0
#endif
201
0
  fz_try(ctx)
202
0
  {
203
0
    state = fz_malloc_struct(ctx, fz_file_stream);
204
0
    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
0
    state->filename = fz_strdup(ctx, name);
216
0
    state->del_on_drop = del_on_drop;
217
218
0
    stm = fz_new_stream(ctx, state, next_file, close_and_drop_file);
219
0
    stm->seek = seek_file;
220
0
  }
221
0
  fz_catch(ctx)
222
0
  {
223
0
    if (state == NULL && del_on_drop)
224
0
    {
225
0
      fclose(file);
226
#ifdef _WIN32
227
      if (wide)
228
        _wunlink((const wchar_t *)name);
229
      else
230
#endif
231
0
        unlink(name);
232
0
    }
233
0
    else
234
0
      close_and_drop_file(ctx, state);
235
0
    fz_rethrow(ctx);
236
0
  }
237
238
0
  return stm;
239
0
}
240
241
fz_stream *fz_open_file_ptr_no_close(fz_context *ctx, FILE *file)
242
0
{
243
0
  fz_stream *stm;
244
0
  fz_file_stream *state = fz_malloc_struct(ctx, fz_file_stream);
245
0
  state->file = file;
246
247
  /* We don't own the file ptr. Ensure we don't close it */
248
0
  stm = fz_new_stream(ctx, state, next_file, drop_file);
249
0
  stm->seek = seek_file;
250
251
0
  return stm;
252
0
}
253
254
fz_stream *
255
fz_open_file(fz_context *ctx, const char *name)
256
0
{
257
0
  FILE *file;
258
#ifdef _WIN32
259
  file = fz_fopen_utf8(name, "rb");
260
#else
261
0
  file = fopen(name, "rb");
262
0
#endif
263
0
  if (file == NULL)
264
0
    fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot open %s: %s", name, strerror(errno));
265
0
  return fz_open_file_ptr(ctx, file, name, 0, 0);
266
0
}
267
268
fz_stream *
269
fz_open_file_autodelete(fz_context *ctx, const char *name)
270
0
{
271
0
  FILE *file;
272
#ifdef _WIN32
273
  file = fz_fopen_utf8(name, "rb");
274
#else
275
0
  file = fopen(name, "rb");
276
0
#endif
277
0
  if (file == NULL)
278
0
    fz_throw(ctx, FZ_ERROR_SYSTEM, "cannot open %s: %s", name, strerror(errno));
279
0
  return fz_open_file_ptr(ctx, file, name, 0, 1);
280
0
}
281
282
fz_stream *
283
fz_try_open_file(fz_context *ctx, const char *name)
284
0
{
285
0
  FILE *file;
286
#ifdef _WIN32
287
  file = fz_fopen_utf8(name, "rb");
288
#else
289
0
  file = fopen(name, "rb");
290
0
#endif
291
0
  if (file == NULL)
292
0
    return NULL;
293
0
  return fz_open_file_ptr(ctx, file, name, 0, 0);
294
0
}
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
0
{
311
0
  if (!stm || stm->next != next_file)
312
0
    return NULL;
313
314
0
  return ((fz_file_stream *)stm->state)->filename;
315
0
}
316
317
/* Memory stream */
318
319
static int next_buffer(fz_context *ctx, fz_stream *stm, size_t max)
320
83.3k
{
321
83.3k
  return EOF;
322
83.3k
}
323
324
static void seek_buffer(fz_context *ctx, fz_stream *stm, int64_t offset, int whence)
325
1.13M
{
326
1.13M
  int64_t pos = stm->pos - (stm->wp - stm->rp);
327
  /* Convert to absolute pos */
328
1.13M
  if (whence == 1)
329
0
  {
330
0
    offset += pos; /* Was relative to current pos */
331
0
  }
332
1.13M
  else if (whence == 2)
333
8.43k
  {
334
8.43k
    offset += stm->pos; /* Was relative to end */
335
8.43k
  }
336
337
1.13M
  if (offset < 0)
338
5
    offset = 0;
339
1.13M
  if (offset > stm->pos)
340
14.0k
    offset = stm->pos;
341
1.13M
  stm->rp += (int)(offset - pos);
342
1.13M
}
343
344
static void drop_buffer(fz_context *ctx, void *state_)
345
59.3k
{
346
59.3k
  fz_buffer *state = (fz_buffer *)state_;
347
59.3k
  fz_drop_buffer(ctx, state);
348
59.3k
}
349
350
fz_stream *
351
fz_open_buffer(fz_context *ctx, fz_buffer *buf)
352
59.3k
{
353
59.3k
  fz_stream *stm;
354
355
59.3k
  if (buf == NULL)
356
0
    return NULL;
357
358
59.3k
  fz_keep_buffer(ctx, buf);
359
59.3k
  stm = fz_new_stream(ctx, buf, next_buffer, drop_buffer);
360
59.3k
  stm->seek = seek_buffer;
361
362
59.3k
  stm->rp = buf->data;
363
59.3k
  stm->wp = buf->data + buf->len;
364
365
59.3k
  stm->pos = (int64_t)buf->len;
366
367
59.3k
  return stm;
368
59.3k
}
369
370
fz_stream *
371
fz_open_memory(fz_context *ctx, const unsigned char *data, size_t len)
372
15.6k
{
373
15.6k
  fz_stream *stm;
374
375
15.6k
  stm = fz_new_stream(ctx, NULL, next_buffer, NULL);
376
15.6k
  stm->seek = seek_buffer;
377
378
15.6k
  stm->rp = (unsigned char *)data;
379
15.6k
  stm->wp = (unsigned char *)data + len;
380
381
15.6k
  stm->pos = (int64_t)len;
382
383
15.6k
  return stm;
384
15.6k
}