Coverage Report

Created: 2025-06-24 07:01

/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
6.15k
{
39
6.15k
}
40
static boolean
41
dcte_empty_output_buffer(j_compress_ptr cinfo)
42
5.47k
{
43
5.47k
    return FALSE;
44
5.47k
}
45
static void
46
dcte_term_destination(j_compress_ptr cinfo)
47
5.80k
{
48
5.80k
}
49
50
/* Set the defaults for the DCTEncode filter. */
51
static void
52
s_DCTE_set_defaults(stream_state * st)
53
6.15k
{
54
6.15k
    stream_DCT_state *const ss = (stream_DCT_state *) st;
55
56
6.15k
    s_DCT_set_defaults(st);
57
6.15k
    ss->QFactor = 1.0;
58
6.15k
    ss->ColorTransform = -1;
59
6.15k
    ss->Markers.data = 0;
60
6.15k
    ss->Markers.size = 0;
61
6.15k
    ss->NoMarker = true;
62
6.15k
}
63
64
/* Initialize DCTEncode filter */
65
static int
66
s_DCTE_init(stream_state * st)
67
6.15k
{
68
6.15k
    stream_DCT_state *const ss = (stream_DCT_state *) st;
69
6.15k
    struct jpeg_destination_mgr *dest = &ss->data.compress->destination;
70
71
6.15k
    dest->init_destination = dcte_init_destination;
72
6.15k
    dest->empty_output_buffer = dcte_empty_output_buffer;
73
6.15k
    dest->term_destination = dcte_term_destination;
74
6.15k
    ss->data.common->memory = ss->jpeg_memory;
75
6.15k
    ss->data.compress->cinfo.dest = dest;
76
6.15k
    ss->phase = 0;
77
6.15k
    ss->icc_marker = 0;
78
6.15k
    ss->icc_position = -1;
79
6.15k
    return 0;
80
6.15k
}
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
109k
{
87
109k
    stream_DCT_state *const ss = (stream_DCT_state *) st;
88
109k
    jpeg_compress_data *jcdp = ss->data.compress;
89
109k
    struct jpeg_destination_mgr *dest = jcdp->cinfo.dest;
90
91
109k
    if_debug2m('w', st->memory, "[wde]process avail=%u, last=%d\n",
92
109k
               (uint) (pr->limit - pr->ptr), last);
93
109k
    dest->next_output_byte = pw->ptr + 1;
94
109k
    dest->free_in_buffer = pw->limit - pw->ptr;
95
109k
    switch (ss->phase) {
96
6.15k
        case 0:   /* not initialized yet */
97
6.15k
            if (gs_jpeg_start_compress(ss, TRUE) < 0)
98
23
                return ERRC;
99
6.15k
            if_debug4m('w', st->memory, "[wde]width=%u, height=%u, components=%d, scan_line_size=%u\n",
100
6.12k
                       jcdp->cinfo.image_width,
101
6.12k
                       jcdp->cinfo.image_height,
102
6.12k
                       jcdp->cinfo.input_components,
103
6.12k
                       ss->scan_line_size);
104
6.12k
            pw->ptr = dest->next_output_byte - 1;
105
6.12k
            ss->phase = 1;
106
            /* falls through */
107
6.12k
        case 1:   /* initialized, Markers not written */
108
6.12k
            if (pw->limit - pw->ptr < ss->Markers.size)
109
0
                return 1;
110
6.12k
            if (ss->Markers.size)
111
0
                memcpy(pw->ptr + 1, ss->Markers.data, ss->Markers.size);
112
6.12k
            pw->ptr += ss->Markers.size;
113
6.12k
            ss->phase = 2;
114
            /* falls through */
115
6.12k
        case 2:   /* still need to write Adobe marker */
116
6.12k
            if (!ss->NoMarker) {
117
6.12k
                static const byte Adobe[] =
118
6.12k
                {
119
6.12k
                    0xFF, JPEG_APP0 + 14, 0, 14, /* parameter length */
120
6.12k
                    'A', 'd', 'o', 'b', 'e',
121
6.12k
                    0, 100, /* Version */
122
6.12k
                    0, 0, /* Flags0 */
123
6.12k
                    0, 0, /* Flags1 */
124
6.12k
                    0   /* ColorTransform */
125
6.12k
                };
126
127
18.3k
#define ADOBE_MARKER_LEN sizeof(Adobe)
128
6.12k
                if (pw->limit - pw->ptr < ADOBE_MARKER_LEN)
129
0
                    return 1;
130
6.12k
                memcpy(pw->ptr + 1, Adobe, ADOBE_MARKER_LEN);
131
6.12k
                pw->ptr += ADOBE_MARKER_LEN;
132
6.12k
                *pw->ptr = ss->ColorTransform;
133
6.12k
#undef ADOBE_MARKER_LEN
134
6.12k
            }
135
6.12k
            dest->next_output_byte = pw->ptr + 1;
136
6.12k
            dest->free_in_buffer = pw->limit - pw->ptr;
137
6.12k
            ss->phase = 3;
138
            /* falls through */
139
6.12k
        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
6.12k
          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
6.12k
          ss->phase = 4;
202
          /* falls through */
203
109k
        case 4:   /* markers written, processing data */
204
687k
            while (jcdp->cinfo.image_height > jcdp->cinfo.next_scanline) {
205
681k
                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
681k
                if_debug1m('w', st->memory, "[wde]next_scanline=%u\n",
218
681k
                           jcdp->cinfo.next_scanline);
219
681k
                if ((uint) (pr->limit - pr->ptr) < ss->scan_line_size) {
220
98.3k
                    if (last)
221
329
                        return ERRC;  /* premature EOD */
222
97.9k
                    return 0; /* need more data */
223
98.3k
                }
224
582k
                written = gs_jpeg_write_scanlines(ss, &samples, 1);
225
582k
                if (written < 0)
226
0
                    return ERRC;
227
582k
                if_debug3m('w', st->memory, "[wde]write returns %d, used=%u, written=%u\n",
228
582k
                           written,
229
582k
                           (uint) (samples - 1 - pr->ptr),
230
582k
                           (uint) (dest->next_output_byte - 1 - pw->ptr));
231
582k
                pw->ptr = dest->next_output_byte - 1;
232
582k
                if (!written)
233
5.47k
                    return 1;  /* output full */
234
577k
                pr->ptr += ss->scan_line_size;
235
577k
            }
236
5.80k
            ss->phase = 5;
237
            /* falls through */
238
5.80k
        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
5.80k
            dest->next_output_byte = jcdp->finish_compress_buf;
243
5.80k
            dest->free_in_buffer = sizeof(jcdp->finish_compress_buf);
244
5.80k
            if (gs_jpeg_finish_compress(ss) < 0)
245
0
                return ERRC;
246
5.80k
            jcdp->fcb_size =
247
5.80k
                dest->next_output_byte - jcdp->finish_compress_buf;
248
5.80k
            jcdp->fcb_pos = 0;
249
5.80k
            ss->phase = 6;
250
            /* falls through */
251
5.80k
        case 6:   /* copy the final data to the output */
252
5.80k
            if (jcdp->fcb_pos < jcdp->fcb_size) {
253
5.80k
                int count = min(jcdp->fcb_size - jcdp->fcb_pos,
254
5.80k
                                pw->limit - pw->ptr);
255
256
5.80k
                if_debug1m('w', st->memory, "[wde]copying final %d\n", count);
257
5.80k
                memcpy(pw->ptr + 1, jcdp->finish_compress_buf + jcdp->fcb_pos,
258
5.80k
                       count);
259
5.80k
                jcdp->fcb_pos += count;
260
5.80k
                pw->ptr += count;
261
5.80k
                if (jcdp->fcb_pos < jcdp->fcb_size)
262
0
                    return 1;
263
5.80k
            }
264
5.80k
            return EOFC;
265
109k
    }
266
    /* Default case can't happen.... */
267
0
    return ERRC;
268
109k
}
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
};