Coverage Report

Created: 2023-06-07 06:20

/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
}