Coverage Report

Created: 2024-08-18 16:21

/home/liu/actions-runner/_work/ccv/ccv/lib/ccv_io.c
Line
Count
Source (jump to first uncovered line)
1
#include "ccv.h"
2
#include "ccv_internal.h"
3
#ifdef HAVE_LIBPNG
4
#ifdef __APPLE__
5
#include "TargetConditionals.h"
6
#if TARGET_OS_IPHONE
7
// iOS
8
#elif TARGET_IPHONE_SIMULATOR
9
// iOS Simulator
10
#elif TARGET_OS_MAC
11
#include <zlib.h>
12
#include <png.h>
13
#else
14
// Unsupported platform
15
#endif
16
#else
17
#include <zlib.h>
18
#include <png.h>
19
#endif
20
#include "io/_ccv_io_libpng.inc"
21
#endif
22
#ifdef HAVE_LIBJPEG
23
#include <jpeglib.h>
24
#include "io/_ccv_io_libjpeg.inc"
25
#endif
26
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
27
#include <sys/param.h>
28
#endif
29
#include "io/_ccv_io_bmp.inc"
30
#include "io/_ccv_io_binary.inc"
31
#include "io/_ccv_io_raw.inc"
32
33
static int _ccv_read_and_close_fd(FILE* fd, ccv_dense_matrix_t** x, int type)
34
86
{
35
86
  int ctype = (type & 0xF00) ? 
CCV_8U | ((type & 0xF00) >> 8)18
:
068
;
36
86
  if ((type & 0XFF) == CCV_IO_ANY_FILE)
37
86
  {
38
86
    unsigned char sig[8];
39
86
    (void) fread(sig, 1, 8, fd);
40
86
    if (memcmp(sig, "\x89\x50\x4e\x47\xd\xa\x1a\xa", 8) == 0)
41
41
      type = CCV_IO_PNG_FILE;
42
45
    else if (memcmp(sig, "\xff\xd8\xff", 3) == 0)
43
4
      type = CCV_IO_JPEG_FILE;
44
41
    else if (memcmp(sig, "BM", 2) == 0)
45
0
      type = CCV_IO_BMP_FILE;
46
41
    else if (memcmp(sig, "CCVBINDM", 8) == 0)
47
41
      type = CCV_IO_BINARY_FILE;
48
86
    fseek(fd, 0, SEEK_SET);
49
86
  }
50
86
  switch (type & 0XFF)
51
86
  {
52
0
#ifdef HAVE_LIBJPEG
53
4
    case CCV_IO_JPEG_FILE:
54
4
      _ccv_read_jpeg_fd(fd, x, ctype);
55
4
      break;
56
0
#endif
57
0
#ifdef HAVE_LIBPNG
58
41
    case CCV_IO_PNG_FILE:
59
41
      _ccv_read_png_fd(fd, x, ctype);
60
41
      break;
61
0
#endif
62
0
    case CCV_IO_BMP_FILE:
63
0
      _ccv_read_bmp_fd(fd, x, ctype);
64
0
      break;
65
41
    case CCV_IO_BINARY_FILE:
66
41
      _ccv_read_binary_fd(fd, x, ctype);
67
86
  }
68
86
  if (*x != 0)
69
86
    ccv_make_matrix_immutable(*x);
70
86
  if (type & CCV_IO_ANY_FILE)
71
86
    fclose(fd);
72
86
  return CCV_IO_FINAL;
73
86
}
74
75
static int _ccv_read_raw(ccv_dense_matrix_t** x, void* data, int type, int rows, int cols, int scanline)
76
20
{
77
20
  assert(rows > 0 && cols > 0 && scanline > 0);
78
20
  if (type & CCV_IO_NO_COPY)
79
1
  {
80
    // there is no conversion that we can apply if it is NO_COPY mode
81
    // NO_COPY mode generate an "unreusable" matrix, which requires you to
82
    // manually release its data block (which is, in fact the same data
83
    // block you passed in)
84
1
    int ctype = CCV_8U | CCV_C1;
85
1
    switch (type & 0xFF)
86
1
    {
87
0
      case CCV_IO_RGB_RAW:
88
0
      case CCV_IO_BGR_RAW:
89
0
        ctype = CCV_8U | CCV_C3;
90
0
        break;
91
0
      case CCV_IO_RGBA_RAW:
92
0
      case CCV_IO_ARGB_RAW:
93
0
      case CCV_IO_BGRA_RAW:
94
0
      case CCV_IO_ABGR_RAW:
95
0
        ctype = CCV_8U | CCV_C4;
96
0
        break;
97
0
      case CCV_IO_GRAY_RAW:
98
1
      default:
99
        /* default one */
100
1
        break;
101
1
    }
102
1
    *x = ccv_dense_matrix_new(rows, cols, ctype | CCV_NO_DATA_ALLOC, data, 0);
103
1
    (*x)->step = scanline;
104
19
  } else {
105
19
    switch (type & 0xFF)
106
19
    {
107
2
      case CCV_IO_RGB_RAW:
108
2
        _ccv_read_rgb_raw(x, data, type, rows, cols, scanline);
109
2
        break;
110
3
      case CCV_IO_RGBA_RAW:
111
3
        _ccv_read_rgba_raw(x, data, type, rows, cols, scanline);
112
3
        break;
113
3
      case CCV_IO_ARGB_RAW:
114
3
        _ccv_read_argb_raw(x, data, type, rows, cols, scanline);
115
3
        break;
116
3
      case CCV_IO_BGR_RAW:
117
3
        _ccv_read_bgr_raw(x, data, type, rows, cols, scanline);
118
3
        break;
119
3
      case CCV_IO_BGRA_RAW:
120
3
        _ccv_read_bgra_raw(x, data, type, rows, cols, scanline);
121
3
        break;
122
3
      case CCV_IO_ABGR_RAW:
123
3
        _ccv_read_abgr_raw(x, data, type, rows, cols, scanline);
124
3
        break;
125
2
      case CCV_IO_GRAY_RAW:
126
2
        _ccv_read_gray_raw(x, data, type, rows, cols, scanline);
127
2
        break;
128
19
    }
129
19
  }
130
20
  if (*x != 0)
131
20
    ccv_make_matrix_immutable(*x);
132
20
  return CCV_IO_FINAL;
133
20
}
134
135
#if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__)
136
137
typedef struct {
138
  char* buffer;
139
  off_t pos;
140
  size_t size;
141
} ccv_io_mem_t;
142
143
static int readfn(void* context, char* buf, int size)
144
{
145
  ccv_io_mem_t* mem = (ccv_io_mem_t*)context;
146
  if (size + mem->pos > mem->size)
147
    size = mem->size - mem->pos;
148
  memcpy(buf, mem->buffer + mem->pos, size);
149
  mem->pos += size;
150
  return size;
151
}
152
153
static off_t seekfn(void* context, off_t off, int whence)
154
{
155
  ccv_io_mem_t* mem = (ccv_io_mem_t*)context;
156
  off_t pos;
157
  switch (whence)
158
  {
159
    case SEEK_SET:
160
      pos = off;
161
      break;
162
    case SEEK_CUR:
163
      pos = mem->pos + off;
164
      break;
165
    case SEEK_END:
166
      pos = mem->size + off;
167
      break;
168
  }
169
  if (pos >= mem->size)
170
    return -1;
171
  mem->pos = pos;
172
  return pos;
173
}
174
175
static int writefn(void* context, const char* buf, int size)
176
{
177
  ccv_io_mem_t* mem = (ccv_io_mem_t*)context;
178
  if (size + mem->pos > mem->size)
179
    return -1;
180
  memcpy(mem->buffer + mem->pos, buf, size);
181
  mem->pos += size;
182
  return size;
183
}
184
#endif
185
186
int ccv_read_impl(const void* in, ccv_dense_matrix_t** x, int type, int rows, int cols, int scanline)
187
106
{
188
106
  FILE* fd = 0;
189
106
  if (type & CCV_IO_ANY_FILE)
190
81
  {
191
81
    assert(rows == 0 && cols == 0 && scanline == 0);
192
81
    fd = fopen((const char*)in, "rb");
193
81
    if (!fd)
194
0
      return CCV_IO_ERROR;
195
81
    return _ccv_read_and_close_fd(fd, x, type);
196
81
  } else 
if (25
type & CCV_IO_ANY_STREAM25
) {
197
5
    assert(rows > 8 && cols == 0 && scanline == 0);
198
5
    assert((type & 0xFF) != CCV_IO_DEFLATE_STREAM); // deflate stream (compressed stream) is not supported yet
199
5
#if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__)
200
    // this is only supported by glibc
201
5
#if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
202
5
    fd = fmemopen((void*)in, (size_t)rows, "rb");
203
#else
204
    ccv_io_mem_t mem = {
205
      .size = rows,
206
      .pos = 0,
207
      .buffer = (char*)in,
208
    };
209
    fd = funopen(&mem, readfn, 0, seekfn, 0);
210
#endif
211
5
    if (!fd)
212
0
      return CCV_IO_ERROR;
213
    // mimicking itself as a "file"
214
5
    type = (type & ~0x10) | 0x20;
215
5
    return _ccv_read_and_close_fd(fd, x, type);
216
5
#endif
217
20
  } else if (type & CCV_IO_ANY_RAW) {
218
20
    return _ccv_read_raw(x, (void*)in /* it can be modifiable if it is NO_COPY mode */, type, rows, cols, scanline);
219
20
  }
220
0
  return CCV_IO_UNKNOWN;
221
106
}
222
223
int ccv_write(ccv_dense_matrix_t* mat, char* const out, size_t* const len, int type, void* conf)
224
9
{
225
9
  FILE* fd = 0;
226
#if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__)
227
  ccv_io_mem_t mem = {0};
228
#endif
229
9
  if (type & CCV_IO_ANY_FILE)
230
3
  {
231
3
    fd = fopen(out, "wb");
232
3
    if (!fd)
233
0
      return CCV_IO_ERROR;
234
6
  } else if ((type & CCV_IO_ANY_STREAM) && type != CCV_IO_PLAIN_STREAM) {
235
4
    assert(len);
236
4
    assert((type & 0xFF) != CCV_IO_DEFLATE_STREAM); // deflate stream (compressed stream) is not supported yet
237
4
#if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__)
238
    // this is only supported by glibc
239
4
#if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
240
4
    fd = fmemopen((void*)out, *len, "wb");
241
#else
242
    mem.size = *len;
243
    mem.buffer = out;
244
    fd = funopen(&mem, 0, writefn, seekfn, 0);
245
#endif
246
4
#endif
247
4
  }
248
9
  int err = 0;
249
9
  switch (type)
250
9
  {
251
1
    case CCV_IO_JPEG_FILE:
252
1
#ifdef HAVE_LIBJPEG
253
1
      err = _ccv_write_jpeg_fd(mat, fd, conf);
254
1
      if (len != 0)
255
0
        *len = 0;
256
#else
257
      assert(0 && "ccv_write requires libjpeg support for JPEG format");
258
#endif
259
1
      break;
260
1
    case CCV_IO_PNG_FILE:
261
1
#ifdef HAVE_LIBPNG
262
1
      err = _ccv_write_png_fd(mat, fd, conf);
263
1
      if (len != 0)
264
0
        *len = 0;
265
#else
266
      assert(0 && "ccv_write requires libpng support for PNG format");
267
#endif
268
1
      break;
269
1
    case CCV_IO_BINARY_FILE:
270
1
      _ccv_write_binary_fd(mat, fd, conf);
271
1
      if (len != 0)
272
0
        *len = 0;
273
1
      break;
274
2
    case CCV_IO_JPEG_STREAM:
275
2
#ifdef HAVE_LIBJPEG
276
2
      err = _ccv_write_jpeg_fd(mat, fd, conf);
277
#else
278
      assert(0 && "ccv_write requires libjpeg support for JPEG format");
279
#endif
280
2
      break;
281
2
    case CCV_IO_PNG_STREAM:
282
2
#ifdef HAVE_LIBPNG
283
2
      err = _ccv_write_png_fd(mat, fd, conf);
284
#else
285
      assert(0 && "ccv_write requires libpng support for PNG format");
286
#endif
287
2
      break;
288
2
    case CCV_IO_PLAIN_STREAM:
289
2
      err = _ccv_write_plain_stream(mat, out, *len);
290
2
      *len = 20 + mat->step * mat->rows;
291
2
      break;
292
9
  }
293
9
  if ((type & CCV_IO_ANY_STREAM) && 
type != CCV_IO_PLAIN_STREAM6
)
294
4
    *len = (size_t)ftell(fd);
295
9
  if (fd)
296
7
    fclose(fd);
297
9
  return err != 0 ? 
CCV_IO_ERROR3
:
CCV_IO_FINAL6
;
298
9
}