Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/sfxcommon.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* $Id: sfxcommon.c 8250 2007-09-25 13:31:24Z giles $ */
18
/* Common routines for stdio and fd file stream implementations. */
19
#include "stdio_.h"   /* includes std.h */
20
#include "memory_.h"
21
#include "unistd_.h"
22
#include "gsmemory.h"
23
#include "gp.h"
24
#include "gserrors.h"
25
#include "stream.h"
26
#include "assert_.h"
27
28
#define DEFAULT_BUFFER_SIZE 2048
29
const uint file_default_buffer_size = DEFAULT_BUFFER_SIZE;
30
31
/* Allocate and return a file stream. */
32
/* Return 0 if the allocation failed. */
33
/* The stream is initialized to an invalid state, so the caller need not */
34
/* worry about cleaning up if a later step in opening the stream fails. */
35
stream *
36
file_alloc_stream(gs_memory_t * mem, client_name_t cname)
37
98.4M
{
38
98.4M
    stream *s;
39
98.4M
    s = s_alloc(mem, cname);
40
98.4M
    if (s == 0)
41
0
        return 0;
42
98.4M
    s_init_ids(s);
43
98.4M
    s->is_temp = 0;   /* not a temp stream */
44
98.4M
    s->foreign = 0;
45
    /*
46
     * Disable the stream now (in case we can't open the file,
47
     * or a filter init procedure fails) so that `restore' won't
48
     * crash when it tries to close open files.
49
     */
50
98.4M
    s_disable(s);
51
98.4M
    s->prev = 0;
52
98.4M
    s->next = 0;
53
98.4M
    return s;
54
98.4M
}
55
56
/* Open a file stream, optionally on an OS file. */
57
/* Return 0 if successful, error code if not. */
58
/* On a successful return, the C file name is in the stream buffer. */
59
/* If fname==0, set up the file entry, stream, and buffer, */
60
/* but don't open an OS file or initialize the stream. */
61
int
62
file_open_stream(const char *fname, uint len, const char *file_access,
63
                 uint buffer_size, stream ** ps, gx_io_device *iodev,
64
                 iodev_proc_fopen_t fopen_proc, gs_memory_t *mem)
65
80.9M
{
66
80.9M
    int code;
67
80.9M
    gp_file *file;
68
80.9M
    char fmode[4];  /* r/w/a, [+], [b], null */
69
70
#ifdef DEBUG
71
    if (strlen(gp_fmode_binary_suffix) > 0) {
72
        if (strchr(file_access, gp_fmode_binary_suffix[0]) != NULL)
73
      dmprintf(mem, "\nWarning: spurious 'b' character in file access mode\n");
74
  assert(strchr(file_access, gp_fmode_binary_suffix[0]) == NULL);
75
    }
76
#endif
77
78
80.9M
    if (!iodev)
79
6.75M
        iodev = iodev_default(mem);
80
80.9M
    code = file_prepare_stream(fname, len, file_access, buffer_size, ps, fmode, mem);
81
80.9M
    if (code < 0)
82
0
        return code;
83
80.9M
    if (fname == 0)
84
6.75M
        return 0;
85
74.2M
    if (fname[0] == 0) {        /* fopen_proc gets NUL terminated string, not len */
86
                                /* so this is the same as len == 0, so return NULL */
87
        /* discard the stuff we allocated to keep from accumulating stuff needing GC */
88
43
        gs_free_object(mem, (*ps)->cbuf, "file_close(buffer)");
89
43
        gs_free_object(mem, *ps, "file_prepare_stream(stream)");
90
43
        *ps = NULL;
91
92
43
        return 0;
93
43
    }
94
74.2M
    code = (*fopen_proc)(iodev, (char *)(*ps)->cbuf, fmode, &file,
95
74.2M
                         (char *)(*ps)->cbuf, (*ps)->bsize, mem);
96
74.2M
    if (code < 0) {
97
        /* discard the stuff we allocated to keep from accumulating stuff needing GC */
98
74.2M
        gs_free_object(mem, (*ps)->cbuf, "file_close(buffer)");
99
74.2M
        gs_free_object(mem, *ps, "file_prepare_stream(stream)");
100
74.2M
        *ps = NULL;
101
74.2M
        return code;
102
74.2M
    }
103
0
    if (file_init_stream(*ps, file, fmode, (*ps)->cbuf, (*ps)->bsize) != 0)
104
0
        return_error(gs_error_ioerror);
105
0
    return 0;
106
0
}
107
108
/* Close a file stream.  This replaces the close procedure in the stream */
109
/* for normal (OS) files and for filters. */
110
int
111
file_close_file(stream * s)
112
6.74M
{
113
6.74M
    stream *stemp = s->strm;
114
6.74M
    gs_memory_t *mem;
115
6.74M
    int code = file_close_disable(s);
116
117
6.74M
    if (code)
118
184k
        return code;
119
    /*
120
     * Check for temporary streams created for filters.
121
     * There may be more than one in the case of a procedure-based filter,
122
     * or if we created an intermediate stream to ensure
123
     * a large enough buffer.  Note that these streams may have been
124
     * allocated by file_alloc_stream, so we mustn't free them.
125
     */
126
7.44M
    while (stemp != 0 && stemp->is_temp != 0) {
127
879k
        stream *snext = stemp->strm;
128
129
879k
        mem = stemp->memory;
130
879k
        if (stemp->is_temp > 1)
131
879k
            gs_free_object(mem, stemp->cbuf,
132
879k
                           "file_close(temp stream buffer)");
133
879k
        s_disable(stemp);
134
879k
        stemp = snext;
135
879k
    }
136
6.56M
    mem = s->memory;
137
6.56M
    gs_free_object(mem, s->cbuf, "file_close(buffer)");
138
6.56M
    if (s->close_strm && stemp != 0)
139
0
        return sclose(stemp);
140
6.56M
    return 0;
141
6.56M
}
142
143
/*
144
 * Set up a file stream on an OS file.  The caller has allocated the
145
 * stream and buffer.
146
 */
147
int
148
file_init_stream(stream *s, gp_file *file, const char *fmode, byte *buffer,
149
                 uint buffer_size)
150
94.5k
{
151
94.5k
    switch (fmode[0]) {
152
0
    case 'a':
153
0
        if (sappend_file(s, file, buffer, buffer_size) != 0)
154
0
            return ERRC;
155
0
        break;
156
0
    case 'r':
157
        /* Defeat buffering for terminals. */
158
0
        {
159
0
            int char_buffered = gp_file_is_char_buffered(file);
160
0
            if (char_buffered < 0)
161
0
                return char_buffered;
162
0
            sread_file(s, file, buffer, char_buffered ? 1 : buffer_size);
163
0
        }
164
0
        break;
165
94.5k
    case 'w':
166
94.5k
        swrite_file(s, file, buffer, buffer_size);
167
94.5k
    }
168
94.5k
    if (fmode[1] == '+')
169
94.5k
        s->file_modes |= s_mode_read | s_mode_write;
170
94.5k
    s->save_close = s->procs.close;
171
94.5k
    s->procs.close = file_close_file;
172
94.5k
    return 0;
173
94.5k
}
174
175
/* Prepare a stream with a file name. */
176
/* Return 0 if successful, error code if not. */
177
/* On a successful return, the C file name is in the stream buffer. */
178
/* If fname==0, set up stream, and buffer. */
179
int
180
file_prepare_stream(const char *fname, uint len, const char *file_access,
181
                 uint buffer_size, stream ** ps, char fmode[4], gs_memory_t *mem)
182
96.4M
{
183
96.4M
    byte *buffer;
184
96.4M
    register stream *s;
185
186
96.4M
    if (strlen(file_access) > 2)
187
0
        return_error(gs_error_invalidfileaccess);
188
189
    /* Open the file, always in binary mode. */
190
96.4M
    strcpy(fmode, file_access);
191
96.4M
    strcat(fmode, gp_fmode_binary_suffix);
192
96.4M
    if (buffer_size == 0)
193
0
        buffer_size = file_default_buffer_size;
194
96.4M
    if (len >= buffer_size)    /* we copy the file name into the buffer */
195
0
        return_error(gs_error_limitcheck);
196
    /* Allocate the stream first, since it persists */
197
    /* even after the file has been closed. */
198
96.4M
    s = file_alloc_stream(mem, "file_prepare_stream");
199
96.4M
    if (s == 0)
200
0
        return_error(gs_error_VMerror);
201
    /* Allocate the buffer. */
202
96.4M
    buffer = gs_alloc_bytes(mem, buffer_size, "file_prepare_stream(buffer)");
203
96.4M
    if (buffer == 0) {
204
0
        gs_free_object(mem, s, "file_prepare_stream");
205
0
        return_error(gs_error_VMerror);
206
0
    }
207
96.4M
    if (fname != 0) {
208
89.7M
        memcpy(buffer, fname, len);
209
89.7M
        buffer[len] = 0;  /* terminate string */
210
89.7M
    } else
211
6.75M
        buffer[0] = 0; /* safety */
212
96.4M
    s->cbuf = buffer;
213
96.4M
    s->bsize = s->cbsize = buffer_size;
214
96.4M
    s->save_close = 0;      /* in case this stream gets disabled before init finishes */
215
96.4M
    *ps = s;
216
96.4M
    return 0;
217
96.4M
}