## Coverage Report

#### Created: 2026-04-20 13:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /home/liu/actions-runner/_work/ccv/ccv/lib/ccv_io.c

    Line
    Count
    Source
    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 (25type & 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
    }