/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 | } |