• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

saitoha / libsixel / 22083462467

17 Feb 2026 01:28AM UTC coverage: 82.459% (-0.02%) from 82.481%
22083462467

push

github

saitoha
loader: add wic ico_minsize suboption and env default

24569 of 48176 branches covered (51.0%)

53 of 87 new or added lines in 2 files covered. (60.92%)

4 existing lines in 2 files now uncovered.

43003 of 52151 relevant lines covered (82.46%)

3707046.18 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.49
/src/loader-common.c
1
/*
2
 * SPDX-License-Identifier: MIT
3
 *
4
 * Copyright (c) 2021-2025 libsixel developers. See `AUTHORS`.
5
 * Copyright (c) 2014-2019 Hayaki Saito
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to
9
 * deal in the Software without restriction, including without limitation the
10
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11
 * sell copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in
15
 * all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
 * FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
 * DEALINGS IN THE SOFTWARE.
24
 *
25
 * Shared loader helpers used across backend implementations.  This module
26
 * centralizes trace logging, thumbnail size hints, and small detection
27
 * helpers so backend files stay narrow and platform headers remain isolated.
28
 */
29

30
#if defined(HAVE_CONFIG_H)
31
#include "config.h"
32
#endif
33

34
#include <stdio.h>
35
#include <stdlib.h>
36

37
#if HAVE_STRING_H
38
# include <string.h>
39
#endif
40
#if HAVE_STDARG_H
41
# include <stdarg.h>
42
#endif
43
#if HAVE_LIMITS_H
44
# include <limits.h>
45
#endif
46
#if HAVE_ERRNO_H
47
# include <errno.h>
48
#endif
49

50
#include <sixel.h>
51

52
#include "compat_stub.h"
53
#include "loader-common.h"
54
#include "logger.h"
55

56
static int loader_trace_enabled;
57
static int thumbnailer_default_size_hint = SIXEL_THUMBNAILER_DEFAULT_SIZE;
58
static int thumbnailer_size_hint = SIXEL_THUMBNAILER_DEFAULT_SIZE;
59
static int thumbnailer_size_hint_initialized;
60
static int wic_ico_minsize_default;
61
static int wic_ico_minsize;
62
static int wic_ico_minsize_initialized;
63

64

65
static void
66
loader_wic_initialize_ico_minsize(void)
490✔
67
{
68
    char const *env_value;
294✔
69
    char *endptr;
294✔
70
    long parsed;
294✔
71

72
    if (wic_ico_minsize_initialized) {
490!
73
        return;
441✔
74
    }
75

76
    wic_ico_minsize_initialized = 1;
490✔
77
    wic_ico_minsize_default = 0;
490✔
78
    wic_ico_minsize = 0;
490✔
79

80
    env_value = sixel_compat_getenv("SIXEL_LODER_WIC_ICO_MINSIZE");
490✔
81
    if (env_value == NULL || env_value[0] == '\0') {
490!
82
        return;
196✔
83
    }
84

NEW
85
    errno = 0;
×
NEW
86
    parsed = strtol(env_value, &endptr, 10);
×
NEW
87
    if (errno != 0) {
×
88
        return;
89
    }
NEW
90
    if (endptr == env_value || *endptr != '\0') {
×
91
        return;
92
    }
NEW
93
    if (parsed <= 0) {
×
94
        return;
95
    }
96
    if (parsed > (long)INT_MAX) {
×
97
        parsed = (long)INT_MAX;
98
    }
99

NEW
100
    wic_ico_minsize_default = (int)parsed;
×
NEW
101
    wic_ico_minsize = wic_ico_minsize_default;
×
102
}
49!
103

104
int
105
loader_wic_get_ico_minsize(void)
490✔
106
{
107
    loader_wic_initialize_ico_minsize();
490✔
108

109
    return wic_ico_minsize;
490✔
110
}
111

112
void
NEW
113
sixel_helper_set_wic_ico_minsize(int size)
×
114
{
NEW
115
    loader_wic_initialize_ico_minsize();
×
116

NEW
117
    if (size > 0) {
×
NEW
118
        wic_ico_minsize = size;
×
119
    } else {
NEW
120
        wic_ico_minsize = wic_ico_minsize_default;
×
121
    }
NEW
122
}
×
123
void
124
loader_thumbnailer_initialize_size_hint(void)
7,767✔
125
{
126
    char const *env_value;
4,841✔
127
    char *endptr;
4,841✔
128
    long parsed;
4,841✔
129

130
    if (thumbnailer_size_hint_initialized) {
7,767✔
131
        return;
4,766✔
132
    }
133

134
    thumbnailer_size_hint_initialized = 1;
7,006✔
135
    thumbnailer_default_size_hint = SIXEL_THUMBNAILER_DEFAULT_SIZE;
7,006✔
136
    thumbnailer_size_hint = thumbnailer_default_size_hint;
7,006✔
137

138
    env_value = sixel_compat_getenv("SIXEL_THUMBNAILER_HINT_SIZE");
7,006✔
139
    if (env_value == NULL || env_value[0] == '\0') {
7,006!
140
        return;
4,091✔
141
    }
142

143
    errno = 0;
27✔
144
    parsed = strtol(env_value, &endptr, 10);
27✔
145
    if (errno != 0) {
27!
146
        return;
7✔
147
    }
148
    if (endptr == env_value || *endptr != '\0') {
20!
149
        return;
150
    }
151
    if (parsed <= 0) {
18✔
152
        return;
7✔
153
    }
154
    if (parsed > (long)INT_MAX) {
9!
155
        parsed = (long)INT_MAX;
156
    }
157

158
    thumbnailer_default_size_hint = (int)parsed;
9✔
159
    thumbnailer_size_hint = thumbnailer_default_size_hint;
9✔
160
}
3,504!
161

162
int
163
loader_thumbnailer_get_size_hint(void)
231✔
164
{
165
    loader_thumbnailer_initialize_size_hint();
231✔
166

167
    return thumbnailer_size_hint;
231✔
168
}
169

170
int
171
loader_thumbnailer_get_default_size_hint(void)
×
172
{
173
    loader_thumbnailer_initialize_size_hint();
×
174

175
    return thumbnailer_default_size_hint;
×
176
}
177

178
void
179
sixel_helper_set_loader_trace(int enable)
7,600✔
180
{
181
    loader_trace_enabled = enable ? 1 : 0;
7,600✔
182
}
7,600✔
183

184
void
185
sixel_helper_set_thumbnail_size_hint(int size)
7,299✔
186
{
187
    loader_thumbnailer_initialize_size_hint();
7,299✔
188

189
    if (size > 0) {
7,299✔
190
        thumbnailer_size_hint = size;
788✔
191
    } else {
370✔
192
        thumbnailer_size_hint = thumbnailer_default_size_hint;
6,511✔
193
    }
194
}
7,299✔
195

196
void
197
loader_trace_message(char const *format, ...)
3,417✔
198
{
199
    va_list args;
2,259✔
200

201
    if (!loader_trace_enabled) {
3,417✔
202
        return;
2,975✔
203
    }
204

205
    fprintf(stderr, "libsixel: ");
442✔
206

207
    va_start(args, format);
442✔
208
    sixel_compat_vfprintf(stderr, format, args);
442✔
209
    va_end(args);
442✔
210

211
    fprintf(stderr, "\n");
442✔
212
}
2,577!
213

214
void
215
loader_trace_try(char const *name)
14,497✔
216
{
217
    if (loader_trace_enabled) {
14,497✔
218
        fprintf(stderr, "libsixel: trying %s loader\n", name);
294✔
219
    }
127✔
220
}
14,497✔
221

222
void
223
loader_trace_result(char const *name, SIXELSTATUS status)
14,497✔
224
{
225
    if (!loader_trace_enabled) {
14,497✔
226
        return;
8,401✔
227
    }
228
    if (SIXEL_SUCCEEDED(status)) {
294!
229
        fprintf(stderr, "libsixel: loader %s succeeded\n", name);
294✔
230
    } else {
127✔
231
        fprintf(stderr, "libsixel: loader %s failed (%s)\n",
×
232
                name, sixel_helper_format_error(status));
233
    }
234
}
6,287✔
235

236
int
237
loader_trace_is_enabled(void)
11,451✔
238
{
239
    return loader_trace_enabled;
11,451✔
240
}
241

242
int
243
chunk_is_png(sixel_chunk_t const *chunk)
5,986✔
244
{
245
    if (chunk == NULL || chunk->size < 8) {
5,986!
246
        return 0;
16✔
247
    }
248

249
    /*
250
     * PNG streams begin with an 8-byte signature.  Checking the fixed magic
251
     * sequence keeps the detection fast and avoids depending on libpng
252
     * helpers when only the signature is needed.
253
     */
254
    if (chunk->buffer[0] == (unsigned char)0x89 &&
8,115!
255
        chunk->buffer[1] == 'P' &&
4,291!
256
        chunk->buffer[2] == 'N' &&
4,291!
257
        chunk->buffer[3] == 'G' &&
4,291!
258
        chunk->buffer[4] == (unsigned char)0x0d &&
4,291!
259
        chunk->buffer[5] == (unsigned char)0x0a &&
4,291!
260
        chunk->buffer[6] == (unsigned char)0x1a &&
4,291!
261
        chunk->buffer[7] == (unsigned char)0x0a) {
4,291!
262
        return 1;
4,291✔
263
    }
264

265
    return 0;
1,479✔
266
}
3,748✔
267

268
int
269
chunk_is_jpeg(sixel_chunk_t const *chunk)
1,240✔
270
{
271
    if (chunk == NULL || chunk->size < 2) {
1,240!
272
        return 0;
273
    }
274

275
    /*
276
     * JPEG files start with SOI (Start of Image) marker 0xFF 0xD8.  The GD
277
     * loader uses this to decide whether libgd should attempt JPEG decoding.
278
     */
279
    if (chunk->buffer[0] == (unsigned char)0xff &&
1,240!
280
        chunk->buffer[1] == (unsigned char)0xd8) {
63!
281
        return 1;
63✔
282
    }
283

284
    return 0;
1,177✔
285
}
1,240✔
286

287
int
288
chunk_is_webp(sixel_chunk_t const *chunk)
1,663✔
289
{
290
    if (chunk == NULL || chunk->size < 12) {
1,663!
291
        return 0;
3✔
292
    }
293

294
    /*
295
     * WebP files use a RIFF container.  The stream starts with \"RIFF\",
296
     * followed by a 32-bit size field, and then the literal \"WEBP\" tag.
297
     */
298
    if (chunk->buffer[0] == 'R' &&
1,660!
299
        chunk->buffer[1] == 'I' &&
×
300
        chunk->buffer[2] == 'F' &&
×
301
        chunk->buffer[3] == 'F' &&
×
302
        chunk->buffer[8] == 'W' &&
×
303
        chunk->buffer[9] == 'E' &&
×
304
        chunk->buffer[10] == 'B' &&
×
305
        chunk->buffer[11] == 'P') {
×
306
        return 1;
×
307
    }
308

309
    return 0;
1,660✔
310
}
1,663✔
311

312
int
313
chunk_is_bmp(sixel_chunk_t const *chunk)
18✔
314
{
315
    if (chunk == NULL || chunk->size < 2) {
18!
316
        return 0;
317
    }
318

319
    /* BMP headers begin with the literal characters 'B' 'M'. */
320
    if (chunk->buffer[0] == 'B' && chunk->buffer[1] == 'M') {
18!
321
        return 1;
×
322
    }
323

324
    return 0;
18✔
325
}
18✔
326

327
int
328
chunk_is_tiff(sixel_chunk_t const *chunk)
1,180✔
329
{
330
    if (chunk == NULL || chunk->size < 4) {
1,180!
331
        return 0;
3✔
332
    }
333

334
    /*
335
     * TIFF headers begin with either "II*\0", "MM\0*", or the BigTIFF
336
     * variants "II+\0"/"MM\0+". Checking the first four bytes is enough to
337
     * decide whether the stream can be probed by libtiff.
338
     */
339
    if ((chunk->buffer[0] == 'I' && chunk->buffer[1] == 'I' &&
1,177!
340
         chunk->buffer[2] == (unsigned char)0x2a &&
21!
341
         chunk->buffer[3] == (unsigned char)0x00) ||
21!
342
        (chunk->buffer[0] == 'M' && chunk->buffer[1] == 'M' &&
1,156!
343
         chunk->buffer[2] == (unsigned char)0x00 &&
×
344
         chunk->buffer[3] == (unsigned char)0x2a) ||
×
345
        (chunk->buffer[0] == 'I' && chunk->buffer[1] == 'I' &&
1,156!
346
         chunk->buffer[2] == (unsigned char)0x2b &&
×
347
         chunk->buffer[3] == (unsigned char)0x00) ||
×
348
        (chunk->buffer[0] == 'M' && chunk->buffer[1] == 'M' &&
1,156!
349
         chunk->buffer[2] == (unsigned char)0x00 &&
×
350
         chunk->buffer[3] == (unsigned char)0x2b)) {
×
351
        return 1;
21✔
352
    }
353

354
    return 0;
1,156✔
355
}
1,180✔
356

357
int
358
chunk_is_gif(sixel_chunk_t const *chunk)
8,373✔
359
{
360
    if (chunk->size < 6) {
8,373✔
361
        return 0;
17✔
362
    }
363
    if (chunk->buffer[0] == 'G' &&
8,431!
364
        chunk->buffer[1] == 'I' &&
291!
365
        chunk->buffer[2] == 'F' &&
291!
366
        chunk->buffer[3] == '8' &&
291!
367
        (chunk->buffer[4] == '7' || chunk->buffer[4] == '9') &&
291!
368
        chunk->buffer[5] == 'a') {
291!
369
        return 1;
291✔
370
    }
371
    return 0;
4,085✔
372
}
2,673✔
373

374
/* emacs Local Variables:      */
375
/* emacs mode: c               */
376
/* emacs tab-width: 4          */
377
/* emacs indent-tabs-mode: nil */
378
/* emacs c-basic-offset: 4     */
379
/* emacs End:                  */
380
/* vim: set expandtab ts=4 sts=4 sw=4 : */
381
/* EOF */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc