Coverage Report

Created: 2025-12-31 07:31

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