Coverage Report

Created: 2025-06-10 07:24

/src/ghostpdl/base/sdcte.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2025 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
/* DCT encoding filter stream */
18
#include "memory_.h"
19
#include "stdio_.h"
20
#include "jpeglib_.h"
21
#include "jerror_.h"
22
#include "gdebug.h"
23
#include "gsmemory.h"
24
#include "strimpl.h"
25
#include "sdct.h"
26
#include "sjpeg.h"
27
28
0
#define ICC_OVERHEAD  16
29
0
#define MAX_MARKER_DATA_SIZE  (65535 - ICC_OVERHEAD)
30
31
public_st_jpeg_compress_data();
32
33
/* ------ DCTEncode ------ */
34
35
/* JPEG destination manager procedures */
36
static void
37
dcte_init_destination(j_compress_ptr cinfo)
38
0
{
39
0
}
40
static boolean
41
dcte_empty_output_buffer(j_compress_ptr cinfo)
42
0
{
43
0
    return FALSE;
44
0
}
45
static void
46
dcte_term_destination(j_compress_ptr cinfo)
47
0
{
48
0
}
49
50
/* Set the defaults for the DCTEncode filter. */
51
static void
52
s_DCTE_set_defaults(stream_state * st)
53
0
{
54
0
    stream_DCT_state *const ss = (stream_DCT_state *) st;
55
56
0
    s_DCT_set_defaults(st);
57
0
    ss->QFactor = 1.0;
58
0
    ss->ColorTransform = -1;
59
0
    ss->Markers.data = 0;
60
0
    ss->Markers.size = 0;
61
0
    ss->NoMarker = true;
62
0
}
63
64
/* Initialize DCTEncode filter */
65
static int
66
s_DCTE_init(stream_state * st)
67
0
{
68
0
    stream_DCT_state *const ss = (stream_DCT_state *) st;
69
0
    struct jpeg_destination_mgr *dest = &ss->data.compress->destination;
70
71
0
    dest->init_destination = dcte_init_destination;
72
0
    dest->empty_output_buffer = dcte_empty_output_buffer;
73
0
    dest->term_destination = dcte_term_destination;
74
0
    ss->data.common->memory = ss->jpeg_memory;
75
0
    ss->data.compress->cinfo.dest = dest;
76
0
    ss->phase = 0;
77
0
    ss->icc_marker = 0;
78
0
    ss->icc_position = -1;
79
0
    return 0;
80
0
}
81
82
/* Process a buffer */
83
static int
84
s_DCTE_process(stream_state * st, stream_cursor_read * pr,
85
               stream_cursor_write * pw, bool last)
86
0
{
87
0
    stream_DCT_state *const ss = (stream_DCT_state *) st;
88
0
    jpeg_compress_data *jcdp = ss->data.compress;
89
0
    struct jpeg_destination_mgr *dest = jcdp->cinfo.dest;
90
91
0
    if_debug2m('w', st->memory, "[wde]process avail=%u, last=%d\n",
92
0
               (uint) (pr->limit - pr->ptr), last);
93
0
    dest->next_output_byte = pw->ptr + 1;
94
0
    dest->free_in_buffer = pw->limit - pw->ptr;
95
0
    switch (ss->phase) {
96
0
        case 0:   /* not initialized yet */
97
0
            if (gs_jpeg_start_compress(ss, TRUE) < 0)
98
0
                return ERRC;
99
0
            if_debug4m('w', st->memory, "[wde]width=%u, height=%u, components=%d, scan_line_size=%u\n",
100
0
                       jcdp->cinfo.image_width,
101
0
                       jcdp->cinfo.image_height,
102
0
                       jcdp->cinfo.input_components,
103
0
                       ss->scan_line_size);
104
0
            pw->ptr = dest->next_output_byte - 1;
105
0
            ss->phase = 1;
106
            /* falls through */
107
0
        case 1:   /* initialized, Markers not written */
108
0
            if (pw->limit - pw->ptr < ss->Markers.size)
109
0
                return 1;
110
0
            if (ss->Markers.size)
111
0
                memcpy(pw->ptr + 1, ss->Markers.data, ss->Markers.size);
112
0
            pw->ptr += ss->Markers.size;
113
0
            ss->phase = 2;
114
            /* falls through */
115
0
        case 2:   /* still need to write Adobe marker */
116
0
            if (!ss->NoMarker) {
117
0
                static const byte Adobe[] =
118
0
                {
119
0
                    0xFF, JPEG_APP0 + 14, 0, 14, /* parameter length */
120
0
                    'A', 'd', 'o', 'b', 'e',
121
0
                    0, 100, /* Version */
122
0
                    0, 0, /* Flags0 */
123
0
                    0, 0, /* Flags1 */
124
0
                    0   /* ColorTransform */
125
0
                };
126
127
0
#define ADOBE_MARKER_LEN sizeof(Adobe)
128
0
                if (pw->limit - pw->ptr < ADOBE_MARKER_LEN)
129
0
                    return 1;
130
0
                memcpy(pw->ptr + 1, Adobe, ADOBE_MARKER_LEN);
131
0
                pw->ptr += ADOBE_MARKER_LEN;
132
0
                *pw->ptr = ss->ColorTransform;
133
0
#undef ADOBE_MARKER_LEN
134
0
            }
135
0
            dest->next_output_byte = pw->ptr + 1;
136
0
            dest->free_in_buffer = pw->limit - pw->ptr;
137
0
            ss->phase = 3;
138
            /* falls through */
139
0
        case  3:
140
            /* If we have it, then write out the ICC profile */
141
            /* Due to size limitations allowed in APP0 markers, the profile
142
               may have to be written in mutiple markers */
143
0
          if (ss->icc_profile != NULL) {
144
0
            static const char marker[2] = {0xFF, 0xE2};  /* JPEG_APP0 + 2 */
145
0
                byte num_mark;
146
147
                /* Number of markers */
148
0
                num_mark = ss->icc_profile->buffer_size / MAX_MARKER_DATA_SIZE;
149
0
                if (num_mark * MAX_MARKER_DATA_SIZE < ss->icc_profile->buffer_size) {
150
0
                    num_mark++;
151
0
                }
152
0
            while (ss->icc_marker < num_mark) {
153
0
                ulong offset = ss->icc_marker * MAX_MARKER_DATA_SIZE;
154
0
                ulong size;
155
156
0
                    size = ss->icc_profile->buffer_size - offset;
157
0
                    if (size > MAX_MARKER_DATA_SIZE)
158
0
                      size = MAX_MARKER_DATA_SIZE;
159
160
                    /* In this case we are just getting started with the
161
                       header of the marker.  Write that portion out */
162
0
                if (ss->icc_position == -1) {
163
0
                  byte length_byte[2];
164
0
                  byte curr_mark = ss->icc_marker + 1;
165
0
                  ulong total_length;
166
167
0
                  if ((uint) (pw->limit - pw->ptr) < (sizeof(marker) + ICC_OVERHEAD))
168
0
                        return 1;
169
0
                  total_length = size + ICC_OVERHEAD;
170
0
                  memcpy(pw->ptr + 1, marker, sizeof(marker));
171
0
                  length_byte[0] = total_length >> 8;
172
0
                  length_byte[1] = total_length & 0xFF;
173
0
                  memcpy(pw->ptr + 3, length_byte, sizeof(length_byte));
174
0
                  memcpy(pw->ptr + 5, "ICC_PROFILE", 12); /* Null included */
175
0
                  memcpy(pw->ptr + 17, &curr_mark, 1);
176
0
                  memcpy(pw->ptr + 18, &num_mark, 1);
177
0
                  pw->ptr += sizeof(marker) + ICC_OVERHEAD;
178
0
                  ss->icc_position = 0;
179
0
                }
180
                    /* Now write out the actual profile data */
181
0
                while (ss->icc_position < size) {
182
0
                  ulong avail_bytes, num_bytes;
183
184
0
                  avail_bytes = (ulong) (pw->limit - pw->ptr);
185
0
                  if (avail_bytes == 0)
186
0
                      return 1;
187
0
                  num_bytes = (size - ss->icc_position);
188
0
                  if (num_bytes > avail_bytes)
189
0
                      num_bytes = avail_bytes;
190
0
                  memcpy(pw->ptr + 1,  ss->icc_profile->buffer + offset + ss->icc_position, num_bytes);
191
0
                  ss->icc_position += num_bytes;
192
0
                  pw->ptr += num_bytes;
193
0
                }
194
                    /* Move on to the next marker */
195
0
                ++ss->icc_marker;
196
0
                ss->icc_position = -1;
197
0
            }
198
0
              dest->next_output_byte = pw->ptr + 1;
199
0
              dest->free_in_buffer = pw->limit - pw->ptr;
200
0
          }
201
0
          ss->phase = 4;
202
          /* falls through */
203
0
        case 4:   /* markers written, processing data */
204
0
            while (jcdp->cinfo.image_height > jcdp->cinfo.next_scanline) {
205
0
                int written;
206
207
                /*
208
                 * The data argument for jpeg_write_scanlines is
209
                 * declared as a JSAMPARRAY.  There is no corresponding
210
                 * const type, so we must remove const from the
211
                 * argument that we are passing here.  (Tom Lane of IJG
212
                 * judges that providing const analogues of the
213
                 * interface types wouldn't be worth the trouble.)
214
                 */
215
                /*const */ byte *samples = (byte *) (pr->ptr + 1);
216
217
0
                if_debug1m('w', st->memory, "[wde]next_scanline=%u\n",
218
0
                           jcdp->cinfo.next_scanline);
219
0
                if ((uint) (pr->limit - pr->ptr) < ss->scan_line_size) {
220
0
                    if (last)
221
0
                        return ERRC; /* premature EOD */
222
0
                    return 0; /* need more data */
223
0
                }
224
0
                written = gs_jpeg_write_scanlines(ss, &samples, 1);
225
0
                if (written < 0)
226
0
                    return ERRC;
227
0
                if_debug3m('w', st->memory, "[wde]write returns %d, used=%u, written=%u\n",
228
0
                           written,
229
0
                           (uint) (samples - 1 - pr->ptr),
230
0
                           (uint) (dest->next_output_byte - 1 - pw->ptr));
231
0
                pw->ptr = dest->next_output_byte - 1;
232
0
                if (!written)
233
0
                    return 1; /* output full */
234
0
                pr->ptr += ss->scan_line_size;
235
0
            }
236
0
            ss->phase = 5;
237
            /* falls through */
238
0
        case 5:   /* all data processed, finishing */
239
            /* jpeg_finish_compress can't suspend, so write its output
240
             * to a fixed-size internal buffer.
241
             */
242
0
            dest->next_output_byte = jcdp->finish_compress_buf;
243
0
            dest->free_in_buffer = sizeof(jcdp->finish_compress_buf);
244
0
            if (gs_jpeg_finish_compress(ss) < 0)
245
0
                return ERRC;
246
0
            jcdp->fcb_size =
247
0
                dest->next_output_byte - jcdp->finish_compress_buf;
248
0
            jcdp->fcb_pos = 0;
249
0
            ss->phase = 6;
250
            /* falls through */
251
0
        case 6:   /* copy the final data to the output */
252
0
            if (jcdp->fcb_pos < jcdp->fcb_size) {
253
0
                int count = min(jcdp->fcb_size - jcdp->fcb_pos,
254
0
                                pw->limit - pw->ptr);
255
256
0
                if_debug1m('w', st->memory, "[wde]copying final %d\n", count);
257
0
                memcpy(pw->ptr + 1, jcdp->finish_compress_buf + jcdp->fcb_pos,
258
0
                       count);
259
0
                jcdp->fcb_pos += count;
260
0
                pw->ptr += count;
261
0
                if (jcdp->fcb_pos < jcdp->fcb_size)
262
0
                    return 1;
263
0
            }
264
0
            return EOFC;
265
0
    }
266
    /* Default case can't happen.... */
267
0
    return ERRC;
268
0
}
269
270
/* Stream template */
271
const stream_template s_DCTE_template =
272
{&st_DCT_state, s_DCTE_init, s_DCTE_process, 1000, 4000, NULL,
273
 s_DCTE_set_defaults
274
};