| File: | ./io/_ccv_io_binary.inc |
| Warning: | line 31, column 2 File position of the stream might be 'indeterminate' after a failed operation. Can cause undefined behavior |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | #include "ccv.h" | ||||
| 2 | #include "ccv_internal.h" | ||||
| 3 | #ifdef HAVE_LIBPNG1 | ||||
| 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_LIBJPEG1 | ||||
| 23 | #include <jpeglib.h> | ||||
| 24 | #include "io/_ccv_io_libjpeg.inc" | ||||
| 25 | #endif | ||||
| 26 | #if defined(__unix__1) || (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 | { | ||||
| 35 | int ctype = (type & 0xF00) ? CCV_8U | ((type & 0xF00) >> 8) : 0; | ||||
| 36 | if ((type & 0XFF) == CCV_IO_ANY_FILE) | ||||
| 37 | { | ||||
| 38 | unsigned char sig[8]; | ||||
| 39 | (void) fread(sig, 1, 8, fd); | ||||
| 40 | if (memcmp(sig, "\x89\x50\x4e\x47\xd\xa\x1a\xa", 8) == 0) | ||||
| 41 | type = CCV_IO_PNG_FILE; | ||||
| 42 | else if (memcmp(sig, "\xff\xd8\xff", 3) == 0) | ||||
| 43 | type = CCV_IO_JPEG_FILE; | ||||
| 44 | else if (memcmp(sig, "BM", 2) == 0) | ||||
| 45 | type = CCV_IO_BMP_FILE; | ||||
| 46 | else if (memcmp(sig, "CCVBINDM", 8) == 0) | ||||
| 47 | type = CCV_IO_BINARY_FILE; | ||||
| 48 | fseek(fd, 0, SEEK_SET0); | ||||
| 49 | } | ||||
| 50 | switch (type & 0XFF) | ||||
| 51 | { | ||||
| 52 | #ifdef HAVE_LIBJPEG1 | ||||
| 53 | case CCV_IO_JPEG_FILE: | ||||
| 54 | _ccv_read_jpeg_fd(fd, x, ctype); | ||||
| 55 | break; | ||||
| 56 | #endif | ||||
| 57 | #ifdef HAVE_LIBPNG1 | ||||
| 58 | case CCV_IO_PNG_FILE: | ||||
| 59 | _ccv_read_png_fd(fd, x, ctype); | ||||
| 60 | break; | ||||
| 61 | #endif | ||||
| 62 | case CCV_IO_BMP_FILE: | ||||
| 63 | _ccv_read_bmp_fd(fd, x, ctype); | ||||
| 64 | break; | ||||
| 65 | case CCV_IO_BINARY_FILE: | ||||
| 66 | _ccv_read_binary_fd(fd, x, ctype); | ||||
| 67 | } | ||||
| 68 | if (*x != 0) | ||||
| 69 | ccv_make_matrix_immutable(*x); | ||||
| 70 | if (type & CCV_IO_ANY_FILE) | ||||
| 71 | fclose(fd); | ||||
| 72 | return CCV_IO_FINAL; | ||||
| 73 | } | ||||
| 74 | |||||
| 75 | static int _ccv_read_raw(ccv_dense_matrix_t** x, void* data, int type, int rows, int cols, int scanline) | ||||
| 76 | { | ||||
| 77 | assert(rows > 0 && cols > 0 && scanline > 0)((void) sizeof ((rows > 0 && cols > 0 && scanline > 0) ? 1 : 0), __extension__ ({ if (rows > 0 && cols > 0 && scanline > 0) ; else __assert_fail ("rows > 0 && cols > 0 && scanline > 0" , "ccv_io.c", 77, __extension__ __PRETTY_FUNCTION__); })); | ||||
| 78 | if (type & CCV_IO_NO_COPY) | ||||
| 79 | { | ||||
| 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 | int ctype = CCV_8U | CCV_C1; | ||||
| 85 | switch (type & 0xFF) | ||||
| 86 | { | ||||
| 87 | case CCV_IO_RGB_RAW: | ||||
| 88 | case CCV_IO_BGR_RAW: | ||||
| 89 | ctype = CCV_8U | CCV_C3; | ||||
| 90 | break; | ||||
| 91 | case CCV_IO_RGBA_RAW: | ||||
| 92 | case CCV_IO_ARGB_RAW: | ||||
| 93 | case CCV_IO_BGRA_RAW: | ||||
| 94 | case CCV_IO_ABGR_RAW: | ||||
| 95 | ctype = CCV_8U | CCV_C4; | ||||
| 96 | break; | ||||
| 97 | case CCV_IO_GRAY_RAW: | ||||
| 98 | default: | ||||
| 99 | /* default one */ | ||||
| 100 | break; | ||||
| 101 | } | ||||
| 102 | *x = ccv_dense_matrix_new(rows, cols, ctype | CCV_NO_DATA_ALLOC, data, 0); | ||||
| 103 | (*x)->step = scanline; | ||||
| 104 | } else { | ||||
| 105 | switch (type & 0xFF) | ||||
| 106 | { | ||||
| 107 | case CCV_IO_RGB_RAW: | ||||
| 108 | _ccv_read_rgb_raw(x, data, type, rows, cols, scanline); | ||||
| 109 | break; | ||||
| 110 | case CCV_IO_RGBA_RAW: | ||||
| 111 | _ccv_read_rgba_raw(x, data, type, rows, cols, scanline); | ||||
| 112 | break; | ||||
| 113 | case CCV_IO_ARGB_RAW: | ||||
| 114 | _ccv_read_argb_raw(x, data, type, rows, cols, scanline); | ||||
| 115 | break; | ||||
| 116 | case CCV_IO_BGR_RAW: | ||||
| 117 | _ccv_read_bgr_raw(x, data, type, rows, cols, scanline); | ||||
| 118 | break; | ||||
| 119 | case CCV_IO_BGRA_RAW: | ||||
| 120 | _ccv_read_bgra_raw(x, data, type, rows, cols, scanline); | ||||
| 121 | break; | ||||
| 122 | case CCV_IO_ABGR_RAW: | ||||
| 123 | _ccv_read_abgr_raw(x, data, type, rows, cols, scanline); | ||||
| 124 | break; | ||||
| 125 | case CCV_IO_GRAY_RAW: | ||||
| 126 | _ccv_read_gray_raw(x, data, type, rows, cols, scanline); | ||||
| 127 | break; | ||||
| 128 | } | ||||
| 129 | } | ||||
| 130 | if (*x != 0) | ||||
| 131 | ccv_make_matrix_immutable(*x); | ||||
| 132 | return CCV_IO_FINAL; | ||||
| 133 | } | ||||
| 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_SET0: | ||||
| 160 | pos = off; | ||||
| 161 | break; | ||||
| 162 | case SEEK_CUR1: | ||||
| 163 | pos = mem->pos + off; | ||||
| 164 | break; | ||||
| 165 | case SEEK_END2: | ||||
| 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 | { | ||||
| 188 | FILE* fd = 0; | ||||
| 189 | if (type & CCV_IO_ANY_FILE) | ||||
| |||||
| 190 | { | ||||
| 191 | assert(rows == 0 && cols == 0 && scanline == 0)((void) sizeof ((rows == 0 && cols == 0 && scanline == 0) ? 1 : 0), __extension__ ({ if (rows == 0 && cols == 0 && scanline == 0) ; else __assert_fail ("rows == 0 && cols == 0 && scanline == 0" , "ccv_io.c", 191, __extension__ __PRETTY_FUNCTION__); })); | ||||
| 192 | fd = fopen((const char*)in, "rb"); | ||||
| 193 | if (!fd
| ||||
| 194 | return CCV_IO_ERROR; | ||||
| 195 | return _ccv_read_and_close_fd(fd, x, type); | ||||
| 196 | } else if (type & CCV_IO_ANY_STREAM) { | ||||
| 197 | assert(rows > 8 && cols == 0 && scanline == 0)((void) sizeof ((rows > 8 && cols == 0 && scanline == 0) ? 1 : 0), __extension__ ({ if (rows > 8 && cols == 0 && scanline == 0) ; else __assert_fail ("rows > 8 && cols == 0 && scanline == 0" , "ccv_io.c", 197, __extension__ __PRETTY_FUNCTION__); })); | ||||
| 198 | assert((type & 0xFF) != CCV_IO_DEFLATE_STREAM)((void) sizeof (((type & 0xFF) != CCV_IO_DEFLATE_STREAM) ? 1 : 0), __extension__ ({ if ((type & 0xFF) != CCV_IO_DEFLATE_STREAM ) ; else __assert_fail ("(type & 0xFF) != CCV_IO_DEFLATE_STREAM" , "ccv_io.c", 198, __extension__ __PRETTY_FUNCTION__); })); // deflate stream (compressed stream) is not supported yet | ||||
| 199 | #if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE200809L >= 200809L || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) | ||||
| 200 | // this is only supported by glibc | ||||
| 201 | #if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE200809L >= 200809L | ||||
| 202 | 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 | if (!fd) | ||||
| 212 | return CCV_IO_ERROR; | ||||
| 213 | // mimicking itself as a "file" | ||||
| 214 | type = (type & ~0x10) | 0x20; | ||||
| 215 | return _ccv_read_and_close_fd(fd, x, type); | ||||
| 216 | #endif | ||||
| 217 | } else if (type & CCV_IO_ANY_RAW) { | ||||
| 218 | return _ccv_read_raw(x, (void*)in /* it can be modifiable if it is NO_COPY mode */, type, rows, cols, scanline); | ||||
| 219 | } | ||||
| 220 | return CCV_IO_UNKNOWN; | ||||
| 221 | } | ||||
| 222 | |||||
| 223 | int ccv_write(ccv_dense_matrix_t* mat, char* const out, size_t* const len, int type, void* conf) | ||||
| 224 | { | ||||
| 225 | FILE* fd = 0; | ||||
| 226 | #if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) | ||||
| 227 | ccv_io_mem_t mem = {0}; | ||||
| 228 | #endif | ||||
| 229 | if (type & CCV_IO_ANY_FILE) | ||||
| 230 | { | ||||
| 231 | fd = fopen(out, "wb"); | ||||
| 232 | if (!fd) | ||||
| 233 | return CCV_IO_ERROR; | ||||
| 234 | } else if ((type & CCV_IO_ANY_STREAM) && type != CCV_IO_PLAIN_STREAM) { | ||||
| 235 | assert(len)((void) sizeof ((len) ? 1 : 0), __extension__ ({ if (len) ; else __assert_fail ("len", "ccv_io.c", 235, __extension__ __PRETTY_FUNCTION__ ); })); | ||||
| 236 | assert((type & 0xFF) != CCV_IO_DEFLATE_STREAM)((void) sizeof (((type & 0xFF) != CCV_IO_DEFLATE_STREAM) ? 1 : 0), __extension__ ({ if ((type & 0xFF) != CCV_IO_DEFLATE_STREAM ) ; else __assert_fail ("(type & 0xFF) != CCV_IO_DEFLATE_STREAM" , "ccv_io.c", 236, __extension__ __PRETTY_FUNCTION__); })); // deflate stream (compressed stream) is not supported yet | ||||
| 237 | #if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE200809L >= 200809L || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) | ||||
| 238 | // this is only supported by glibc | ||||
| 239 | #if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE200809L >= 200809L | ||||
| 240 | 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 | #endif | ||||
| 247 | } | ||||
| 248 | int err = 0; | ||||
| 249 | switch (type) | ||||
| 250 | { | ||||
| 251 | case CCV_IO_JPEG_FILE: | ||||
| 252 | #ifdef HAVE_LIBJPEG1 | ||||
| 253 | err = _ccv_write_jpeg_fd(mat, fd, conf); | ||||
| 254 | if (len != 0) | ||||
| 255 | *len = 0; | ||||
| 256 | #else | ||||
| 257 | assert(0 && "ccv_write requires libjpeg support for JPEG format")((void) sizeof ((0 && "ccv_write requires libjpeg support for JPEG format" ) ? 1 : 0), __extension__ ({ if (0 && "ccv_write requires libjpeg support for JPEG format" ) ; else __assert_fail ("0 && \"ccv_write requires libjpeg support for JPEG format\"" , "ccv_io.c", 257, __extension__ __PRETTY_FUNCTION__); })); | ||||
| 258 | #endif | ||||
| 259 | break; | ||||
| 260 | case CCV_IO_PNG_FILE: | ||||
| 261 | #ifdef HAVE_LIBPNG1 | ||||
| 262 | err = _ccv_write_png_fd(mat, fd, conf); | ||||
| 263 | if (len != 0) | ||||
| 264 | *len = 0; | ||||
| 265 | #else | ||||
| 266 | assert(0 && "ccv_write requires libpng support for PNG format")((void) sizeof ((0 && "ccv_write requires libpng support for PNG format" ) ? 1 : 0), __extension__ ({ if (0 && "ccv_write requires libpng support for PNG format" ) ; else __assert_fail ("0 && \"ccv_write requires libpng support for PNG format\"" , "ccv_io.c", 266, __extension__ __PRETTY_FUNCTION__); })); | ||||
| 267 | #endif | ||||
| 268 | break; | ||||
| 269 | case CCV_IO_BINARY_FILE: | ||||
| 270 | _ccv_write_binary_fd(mat, fd, conf); | ||||
| 271 | if (len != 0) | ||||
| 272 | *len = 0; | ||||
| 273 | break; | ||||
| 274 | case CCV_IO_JPEG_STREAM: | ||||
| 275 | #ifdef HAVE_LIBJPEG1 | ||||
| 276 | err = _ccv_write_jpeg_fd(mat, fd, conf); | ||||
| 277 | #else | ||||
| 278 | assert(0 && "ccv_write requires libjpeg support for JPEG format")((void) sizeof ((0 && "ccv_write requires libjpeg support for JPEG format" ) ? 1 : 0), __extension__ ({ if (0 && "ccv_write requires libjpeg support for JPEG format" ) ; else __assert_fail ("0 && \"ccv_write requires libjpeg support for JPEG format\"" , "ccv_io.c", 278, __extension__ __PRETTY_FUNCTION__); })); | ||||
| 279 | #endif | ||||
| 280 | break; | ||||
| 281 | case CCV_IO_PNG_STREAM: | ||||
| 282 | #ifdef HAVE_LIBPNG1 | ||||
| 283 | err = _ccv_write_png_fd(mat, fd, conf); | ||||
| 284 | #else | ||||
| 285 | assert(0 && "ccv_write requires libpng support for PNG format")((void) sizeof ((0 && "ccv_write requires libpng support for PNG format" ) ? 1 : 0), __extension__ ({ if (0 && "ccv_write requires libpng support for PNG format" ) ; else __assert_fail ("0 && \"ccv_write requires libpng support for PNG format\"" , "ccv_io.c", 285, __extension__ __PRETTY_FUNCTION__); })); | ||||
| 286 | #endif | ||||
| 287 | break; | ||||
| 288 | case CCV_IO_PLAIN_STREAM: | ||||
| 289 | err = _ccv_write_plain_stream(mat, out, *len); | ||||
| 290 | *len = 20 + mat->step * mat->rows; | ||||
| 291 | break; | ||||
| 292 | } | ||||
| 293 | if ((type & CCV_IO_ANY_STREAM) && type != CCV_IO_PLAIN_STREAM) | ||||
| 294 | *len = (size_t)ftell(fd); | ||||
| 295 | if (fd) | ||||
| 296 | fclose(fd); | ||||
| 297 | return err != 0 ? CCV_IO_ERROR : CCV_IO_FINAL; | ||||
| 298 | } |
| 1 | static void _ccv_write_binary_fd(ccv_dense_matrix_t* mat, FILE* fd, void* conf) | |||
| 2 | { | |||
| 3 | fwrite("CCVBINDM", 1, 8, fd); | |||
| 4 | int ctype = mat->type & 0xFFFFF; | |||
| 5 | fwrite(&ctype, 1, 4, fd); | |||
| 6 | fwrite(&(mat->rows), 1, 4, fd); | |||
| 7 | fwrite(&(mat->cols), 1, 4, fd); | |||
| 8 | fwrite(mat->data.u8, 1, mat->step * mat->rows, fd); | |||
| 9 | fflush(fd); | |||
| 10 | } | |||
| 11 | ||||
| 12 | static int _ccv_write_plain_stream(ccv_dense_matrix_t* mat, void* buf, size_t len) | |||
| 13 | { | |||
| 14 | if (len < 20 + mat->step * mat->rows) | |||
| 15 | return -1; | |||
| 16 | memcpy(buf, "CCVBINDM", 8); | |||
| 17 | int ctype = mat->type & 0xFFFFF; | |||
| 18 | memcpy(buf + 8, &ctype, 4); | |||
| 19 | memcpy(buf + 12, &mat->rows, 4); | |||
| 20 | memcpy(buf + 16, &mat->cols, 4); | |||
| 21 | memcpy(buf + 20, mat->data.u8, mat->step * mat->rows); | |||
| 22 | return 0; | |||
| 23 | } | |||
| 24 | ||||
| 25 | static void _ccv_read_binary_fd(FILE* in, ccv_dense_matrix_t** x, int type) | |||
| 26 | { | |||
| 27 | fseek(in, 8, SEEK_SET0); | |||
| 28 | fread(&type, 1, 4, in); | |||
| 29 | int rows, cols; | |||
| 30 | fread(&rows, 1, 4, in); | |||
| 31 | fread(&cols, 1, 4, in); | |||
| ||||
| 32 | *x = ccv_dense_matrix_new(rows, cols, type, 0, 0); | |||
| 33 | fread((*x)->data.u8, 1, (*x)->step * (*x)->rows, in); | |||
| 34 | } |