/src/libraw/src/libraw_datastream.cpp
Line | Count | Source |
1 | | /* -*- C++ -*- |
2 | | * File: libraw_datastream.cpp |
3 | | * Copyright 2008-2025 LibRaw LLC (info@libraw.org) |
4 | | * |
5 | | * LibRaw C++ interface (implementation) |
6 | | |
7 | | LibRaw is free software; you can redistribute it and/or modify |
8 | | it under the terms of the one of two licenses as you choose: |
9 | | |
10 | | 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 |
11 | | (See file LICENSE.LGPL provided in LibRaw distribution archive for details). |
12 | | |
13 | | 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 |
14 | | (See file LICENSE.CDDL provided in LibRaw distribution archive for details). |
15 | | |
16 | | */ |
17 | | |
18 | | #ifdef _WIN32 |
19 | | #ifdef __MINGW32__ |
20 | | #define _WIN32_WINNT 0x0500 |
21 | | #include <stdexcept> |
22 | | #endif |
23 | | #endif |
24 | | |
25 | | #define LIBRAW_LIBRARY_BUILD |
26 | | #include "libraw/libraw.h" |
27 | | #include "libraw/libraw_types.h" |
28 | | #include "libraw/libraw_datastream.h" |
29 | | #include <sys/stat.h> |
30 | | #ifdef USE_JPEG |
31 | | #include <jpeglib.h> |
32 | | #include <jerror.h> |
33 | | #else |
34 | | #define NO_JPEG |
35 | | #endif |
36 | | |
37 | | #ifdef USE_JPEG |
38 | | |
39 | | typedef struct |
40 | | { |
41 | | struct jpeg_source_mgr pub; /* public fields */ |
42 | | LibRaw_abstract_datastream *instream; /* source stream */ |
43 | | JOCTET *buffer; /* start of buffer */ |
44 | | boolean start_of_file; /* have we gotten any data yet? */ |
45 | | } lr_jpg_source_mgr; |
46 | | |
47 | | typedef lr_jpg_source_mgr *lr_jpg_src_ptr; |
48 | | |
49 | | #define LR_JPEG_INPUT_BUF_SIZE 16384 |
50 | | |
51 | | static void f_init_source(j_decompress_ptr cinfo) |
52 | | { |
53 | | lr_jpg_src_ptr src = (lr_jpg_src_ptr)cinfo->src; |
54 | | src->start_of_file = TRUE; |
55 | | } |
56 | | |
57 | | #ifdef ERREXIT |
58 | | #undef ERREXIT |
59 | | #endif |
60 | | |
61 | | #define ERREXIT(cinfo, code) \ |
62 | | ((cinfo)->err->msg_code = (code), \ |
63 | | (*(cinfo)->err->error_exit)((j_common_ptr)(cinfo))) |
64 | | |
65 | | static boolean lr_fill_input_buffer(j_decompress_ptr cinfo) |
66 | | { |
67 | | lr_jpg_src_ptr src = (lr_jpg_src_ptr)cinfo->src; |
68 | | size_t nbytes; |
69 | | |
70 | | nbytes = src->instream->read((void*)src->buffer, 1, LR_JPEG_INPUT_BUF_SIZE); |
71 | | |
72 | | if (nbytes <= 0) |
73 | | { |
74 | | if (src->start_of_file) /* Treat empty input file as fatal error */ |
75 | | ERREXIT(cinfo, JERR_INPUT_EMPTY); |
76 | | WARNMS(cinfo, JWRN_JPEG_EOF); |
77 | | /* Insert a fake EOI marker */ |
78 | | src->buffer[0] = (JOCTET)0xFF; |
79 | | src->buffer[1] = (JOCTET)JPEG_EOI; |
80 | | nbytes = 2; |
81 | | } |
82 | | |
83 | | src->pub.next_input_byte = src->buffer; |
84 | | src->pub.bytes_in_buffer = nbytes; |
85 | | src->start_of_file = FALSE; |
86 | | return TRUE; |
87 | | } |
88 | | |
89 | | static void lr_skip_input_data(j_decompress_ptr cinfo, long num_bytes) |
90 | | { |
91 | | struct jpeg_source_mgr *src = cinfo->src; |
92 | | if (num_bytes > 0) |
93 | | { |
94 | | while (num_bytes > (long)src->bytes_in_buffer) |
95 | | { |
96 | | num_bytes -= (long)src->bytes_in_buffer; |
97 | | (void)(*src->fill_input_buffer)(cinfo); |
98 | | /* note we assume that fill_input_buffer will never return FALSE, |
99 | | * so suspension need not be handled. |
100 | | */ |
101 | | } |
102 | | src->next_input_byte += (size_t)num_bytes; |
103 | | src->bytes_in_buffer -= (size_t)num_bytes; |
104 | | } |
105 | | } |
106 | | |
107 | | static void lr_term_source(j_decompress_ptr /*cinfo*/) {} |
108 | | |
109 | | static void lr_jpeg_src(j_decompress_ptr cinfo, LibRaw_abstract_datastream *inf) |
110 | | { |
111 | | lr_jpg_src_ptr src; |
112 | | if (cinfo->src == NULL) |
113 | | { /* first time for this JPEG object? */ |
114 | | cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small)( |
115 | | (j_common_ptr)cinfo, JPOOL_PERMANENT, sizeof(lr_jpg_source_mgr)); |
116 | | src = (lr_jpg_src_ptr)cinfo->src; |
117 | | src->buffer = (JOCTET *)(*cinfo->mem->alloc_small)( |
118 | | (j_common_ptr)cinfo, JPOOL_PERMANENT, |
119 | | LR_JPEG_INPUT_BUF_SIZE * sizeof(JOCTET)); |
120 | | } |
121 | | else if (cinfo->src->init_source != f_init_source) |
122 | | { |
123 | | ERREXIT(cinfo, JERR_BUFFER_SIZE); |
124 | | } |
125 | | |
126 | | src = (lr_jpg_src_ptr)cinfo->src; |
127 | | src->pub.init_source = f_init_source; |
128 | | src->pub.fill_input_buffer = lr_fill_input_buffer; |
129 | | src->pub.skip_input_data = lr_skip_input_data; |
130 | | src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ |
131 | | src->pub.term_source = lr_term_source; |
132 | | src->instream = inf; |
133 | | src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ |
134 | | src->pub.next_input_byte = NULL; /* until buffer loaded */ |
135 | | } |
136 | | #endif |
137 | | |
138 | | int LibRaw_abstract_datastream::jpeg_src(void *jpegdata) |
139 | 0 | { |
140 | 0 | #ifdef NO_JPEG |
141 | 0 | return -1; |
142 | | #else |
143 | | j_decompress_ptr cinfo = (j_decompress_ptr)jpegdata; |
144 | | buffering_off(); |
145 | | lr_jpeg_src(cinfo, this); |
146 | | return 0; // OK |
147 | | #endif |
148 | 0 | } |
149 | | |
150 | | |
151 | | #ifndef LIBRAW_NO_IOSTREAMS_DATASTREAM |
152 | | // == LibRaw_file_datastream == |
153 | | |
154 | | LibRaw_file_datastream::LibRaw_file_datastream(const char *fname) |
155 | | : filename(fname), _fsize(0) |
156 | | #ifdef LIBRAW_WIN32_UNICODEPATHS |
157 | | , |
158 | | wfilename() |
159 | | #endif |
160 | | { |
161 | | if (filename.size() > 0) |
162 | | { |
163 | | #ifndef LIBRAW_WIN32_CALLS |
164 | | struct stat st; |
165 | | if (!stat(filename.c_str(), &st)) |
166 | | _fsize = st.st_size; |
167 | | #else |
168 | | struct _stati64 st; |
169 | | if (!_stati64(filename.c_str(), &st)) |
170 | | _fsize = st.st_size; |
171 | | #endif |
172 | | #ifdef LIBRAW_USE_AUTOPTR |
173 | | std::auto_ptr<std::filebuf> buf(new std::filebuf()); |
174 | | #else |
175 | | std::unique_ptr<std::filebuf> buf(new std::filebuf()); |
176 | | #endif |
177 | | buf->open(filename.c_str(), std::ios_base::in | std::ios_base::binary); |
178 | | if (buf->is_open()) |
179 | | { |
180 | | #ifdef LIBRAW_USE_AUTOPTR |
181 | | f = buf; |
182 | | #else |
183 | | f = std::move(buf); |
184 | | #endif |
185 | | } |
186 | | } |
187 | | } |
188 | | #ifdef LIBRAW_WIN32_UNICODEPATHS |
189 | | LibRaw_file_datastream::LibRaw_file_datastream(const wchar_t *fname) |
190 | | : filename(), wfilename(fname), _fsize(0) |
191 | | { |
192 | | if (wfilename.size() > 0) |
193 | | { |
194 | | struct _stati64 st; |
195 | | if (!_wstati64(wfilename.c_str(), &st)) |
196 | | _fsize = st.st_size; |
197 | | #ifdef LIBRAW_USE_AUTOPTR |
198 | | std::auto_ptr<std::filebuf> buf(new std::filebuf()); |
199 | | #else |
200 | | std::unique_ptr<std::filebuf> buf(new std::filebuf()); |
201 | | #endif |
202 | | buf->open(wfilename.c_str(), std::ios_base::in | std::ios_base::binary); |
203 | | if (buf->is_open()) |
204 | | { |
205 | | #ifdef LIBRAW_USE_AUTOPTR |
206 | | f = buf; |
207 | | #else |
208 | | f = std::move(buf); |
209 | | #endif |
210 | | } |
211 | | } |
212 | | } |
213 | | const wchar_t *LibRaw_file_datastream::wfname() |
214 | | { |
215 | | return wfilename.size() > 0 ? wfilename.c_str() : NULL; |
216 | | } |
217 | | #endif |
218 | | |
219 | | int LibRaw_file_datastream::valid() { return f.get() ? 1 : 0; } |
220 | | |
221 | | #define LR_STREAM_CHK() \ |
222 | | do \ |
223 | | { \ |
224 | | if (!f.get()) \ |
225 | | throw LIBRAW_EXCEPTION_IO_EOF; \ |
226 | | } while (0) |
227 | | |
228 | | int LibRaw_file_datastream::read(void *ptr, size_t size, size_t nmemb) |
229 | | { |
230 | | /* Visual Studio 2008 marks sgetn as insecure, but VS2010 does not. */ |
231 | | #if defined(WIN32SECURECALLS) && (_MSC_VER < 1600) |
232 | | LR_STREAM_CHK(); |
233 | | return int(f->_Sgetn_s(static_cast<char *>(ptr), nmemb * size, nmemb * size) / |
234 | | (size > 0 ? size : 1)); |
235 | | #else |
236 | | LR_STREAM_CHK(); |
237 | | return int(f->sgetn(static_cast<char *>(ptr), std::streamsize(nmemb * size)) / |
238 | | (size > 0 ? size : 1)); |
239 | | #endif |
240 | | } |
241 | | |
242 | | int LibRaw_file_datastream::eof() |
243 | | { |
244 | | LR_STREAM_CHK(); |
245 | | return f->sgetc() == EOF; |
246 | | } |
247 | | |
248 | | int LibRaw_file_datastream::seek(INT64 o, int whence) |
249 | | { |
250 | | LR_STREAM_CHK(); |
251 | | std::ios_base::seekdir dir; |
252 | | switch (whence) |
253 | | { |
254 | | case SEEK_SET: |
255 | | dir = std::ios_base::beg; |
256 | | break; |
257 | | case SEEK_CUR: |
258 | | dir = std::ios_base::cur; |
259 | | break; |
260 | | case SEEK_END: |
261 | | dir = std::ios_base::end; |
262 | | break; |
263 | | default: |
264 | | dir = std::ios_base::beg; |
265 | | } |
266 | | return f->pubseekoff((long)o, dir) < 0; |
267 | | } |
268 | | |
269 | | INT64 LibRaw_file_datastream::tell() |
270 | | { |
271 | | LR_STREAM_CHK(); |
272 | | return f->pubseekoff(0, std::ios_base::cur); |
273 | | } |
274 | | |
275 | | char *LibRaw_file_datastream::gets(char *str, int sz) |
276 | | { |
277 | | if(sz<1) return NULL; |
278 | | LR_STREAM_CHK(); |
279 | | std::istream is(f.get()); |
280 | | is.getline(str, sz); |
281 | | if (is.fail()) |
282 | | return 0; |
283 | | return str; |
284 | | } |
285 | | |
286 | | int LibRaw_file_datastream::scanf_one(const char *fmt, void *val) |
287 | | { |
288 | | LR_STREAM_CHK(); |
289 | | |
290 | | std::istream is(f.get()); |
291 | | |
292 | | /* HUGE ASSUMPTION: *fmt is either "%d" or "%f" */ |
293 | | if (strcmp(fmt, "%d") == 0) |
294 | | { |
295 | | int d; |
296 | | is >> d; |
297 | | if (is.fail()) |
298 | | return EOF; |
299 | | *(static_cast<int *>(val)) = d; |
300 | | } |
301 | | else |
302 | | { |
303 | | float f; |
304 | | is >> f; |
305 | | if (is.fail()) |
306 | | return EOF; |
307 | | *(static_cast<float *>(val)) = f; |
308 | | } |
309 | | |
310 | | return 1; |
311 | | } |
312 | | |
313 | | const char *LibRaw_file_datastream::fname() |
314 | | { |
315 | | return filename.size() > 0 ? filename.c_str() : NULL; |
316 | | } |
317 | | |
318 | | #undef LR_STREAM_CHK |
319 | | |
320 | | #endif |
321 | | |
322 | | // == LibRaw_buffer_datastream |
323 | | LibRaw_buffer_datastream::LibRaw_buffer_datastream(const void *buffer, size_t bsize) |
324 | 0 | { |
325 | 0 | buf = (unsigned char *)buffer; |
326 | 0 | streampos = 0; |
327 | 0 | streamsize = bsize; |
328 | 0 | } |
329 | | |
330 | 0 | LibRaw_buffer_datastream::~LibRaw_buffer_datastream() {} |
331 | | |
332 | | int LibRaw_buffer_datastream::read(void *ptr, size_t sz, size_t nmemb) |
333 | 0 | { |
334 | 0 | size_t to_read = sz * nmemb; |
335 | 0 | if (to_read > streamsize - streampos) |
336 | 0 | to_read = streamsize - streampos; |
337 | 0 | if (to_read < 1) |
338 | 0 | return 0; |
339 | 0 | memmove(ptr, buf + streampos, to_read); |
340 | 0 | streampos += to_read; |
341 | 0 | return int((to_read + sz - 1) / (sz > 0 ? sz : 1)); |
342 | 0 | } |
343 | | |
344 | | int LibRaw_buffer_datastream::seek(INT64 o, int whence) |
345 | 0 | { |
346 | 0 | switch (whence) |
347 | 0 | { |
348 | 0 | case SEEK_SET: |
349 | 0 | if (o < 0) |
350 | 0 | streampos = 0; |
351 | 0 | else if (size_t(o) > streamsize) |
352 | 0 | streampos = streamsize; |
353 | 0 | else |
354 | 0 | streampos = size_t(o); |
355 | 0 | return 0; |
356 | 0 | case SEEK_CUR: |
357 | 0 | if (o < 0) |
358 | 0 | { |
359 | 0 | if (size_t(-o) >= streampos) |
360 | 0 | streampos = 0; |
361 | 0 | else |
362 | 0 | streampos += (size_t)o; |
363 | 0 | } |
364 | 0 | else if (o > 0) |
365 | 0 | { |
366 | 0 | if (o + streampos > streamsize) |
367 | 0 | streampos = streamsize; |
368 | 0 | else |
369 | 0 | streampos += (size_t)o; |
370 | 0 | } |
371 | 0 | return 0; |
372 | 0 | case SEEK_END: |
373 | 0 | if (o > 0) |
374 | 0 | streampos = streamsize; |
375 | 0 | else if (size_t(-o) > streamsize) |
376 | 0 | streampos = 0; |
377 | 0 | else |
378 | 0 | streampos = streamsize + (size_t)o; |
379 | 0 | return 0; |
380 | 0 | default: |
381 | 0 | return 0; |
382 | 0 | } |
383 | 0 | } |
384 | | |
385 | | INT64 LibRaw_buffer_datastream::tell() |
386 | 0 | { |
387 | 0 | return INT64(streampos); |
388 | 0 | } |
389 | | |
390 | | char *LibRaw_buffer_datastream::gets(char *s, int sz) |
391 | 0 | { |
392 | 0 | if(sz<1) return NULL; |
393 | 0 | unsigned char *psrc, *pdest, *str; |
394 | 0 | str = (unsigned char *)s; |
395 | 0 | psrc = buf + streampos; |
396 | 0 | pdest = str; |
397 | 0 | if(streampos >= streamsize) return NULL; |
398 | 0 | while ((size_t(psrc - buf) < streamsize) && ((pdest - str) < (sz-1))) |
399 | 0 | { |
400 | 0 | *pdest = *psrc; |
401 | 0 | if (*psrc == '\n') |
402 | 0 | break; |
403 | 0 | psrc++; |
404 | 0 | pdest++; |
405 | 0 | } |
406 | 0 | if (size_t(psrc - buf) < streamsize) |
407 | 0 | psrc++; |
408 | 0 | if ((pdest - str) < sz-1) |
409 | 0 | *(++pdest) = 0; |
410 | 0 | else |
411 | 0 | s[sz - 1] = 0; // ensure trailing zero |
412 | |
|
413 | 0 | streampos = psrc - buf; |
414 | 0 | return s; |
415 | 0 | } |
416 | | |
417 | | int LibRaw_buffer_datastream::scanf_one(const char *fmt, void *val) |
418 | 0 | { |
419 | 0 | int scanf_res; |
420 | 0 | if (streampos > streamsize-24) // we assume at least 24 bytes in buffer, same assumption as in bigfile buffered datastream |
421 | 0 | return 0; |
422 | 0 | char scanf_buffer[25]; |
423 | 0 | memcpy(scanf_buffer, buf + streampos, 24); |
424 | 0 | scanf_buffer[24] = 0; |
425 | 0 | #ifndef WIN32SECURECALLS |
426 | 0 | scanf_res = sscanf(scanf_buffer, fmt, val); |
427 | | #else |
428 | | scanf_res = sscanf_s(scanf_buffer, fmt, val); |
429 | | #endif |
430 | 0 | if (scanf_res > 0) |
431 | 0 | { |
432 | 0 | int xcnt = 0; |
433 | 0 | while (streampos < streamsize-1) |
434 | 0 | { |
435 | 0 | streampos++; |
436 | 0 | xcnt++; |
437 | 0 | if (buf[streampos] == 0 || buf[streampos] == ' ' || |
438 | 0 | buf[streampos] == '\t' || buf[streampos] == '\n' || xcnt > 24) |
439 | 0 | break; |
440 | 0 | } |
441 | 0 | } |
442 | 0 | return scanf_res; |
443 | 0 | } |
444 | | |
445 | | int LibRaw_buffer_datastream::eof() |
446 | 0 | { |
447 | 0 | return streampos >= streamsize; |
448 | 0 | } |
449 | 0 | int LibRaw_buffer_datastream::valid() { return buf ? 1 : 0; } |
450 | | |
451 | | |
452 | | int LibRaw_buffer_datastream::jpeg_src(void *jpegdata) |
453 | 0 | { |
454 | 0 | #if defined(NO_JPEG) || !defined(USE_JPEG) |
455 | 0 | return -1; |
456 | | #else |
457 | | j_decompress_ptr cinfo = (j_decompress_ptr)jpegdata; |
458 | | jpeg_mem_src(cinfo, (unsigned char *)buf + streampos,(unsigned long)(streamsize - streampos)); |
459 | | return 0; |
460 | | #endif |
461 | 0 | } |
462 | | |
463 | | // int LibRaw_buffer_datastream |
464 | | |
465 | | // == LibRaw_bigfile_datastream |
466 | | LibRaw_bigfile_datastream::LibRaw_bigfile_datastream(const char *fname) |
467 | 39.8k | : filename(fname) |
468 | | #ifdef LIBRAW_WIN32_UNICODEPATHS |
469 | | , |
470 | | wfilename() |
471 | | #endif |
472 | 39.8k | { |
473 | 39.8k | if (filename.size() > 0) |
474 | 39.8k | { |
475 | 39.8k | #ifndef LIBRAW_WIN32_CALLS |
476 | 39.8k | struct stat st; |
477 | 39.8k | if (!stat(filename.c_str(), &st)) |
478 | 39.8k | _fsize = st.st_size; |
479 | | #else |
480 | | struct _stati64 st; |
481 | | if (!_stati64(filename.c_str(), &st)) |
482 | | _fsize = st.st_size; |
483 | | #endif |
484 | | |
485 | 39.8k | #ifndef WIN32SECURECALLS |
486 | 39.8k | f = fopen(fname, "rb"); |
487 | | #else |
488 | | if (fopen_s(&f, fname, "rb")) |
489 | | f = 0; |
490 | | #endif |
491 | 39.8k | } |
492 | 0 | else |
493 | 0 | { |
494 | 0 | filename = std::string(); |
495 | 0 | f = 0; |
496 | 0 | } |
497 | 39.8k | } |
498 | | |
499 | | #ifdef LIBRAW_WIN32_UNICODEPATHS |
500 | | LibRaw_bigfile_datastream::LibRaw_bigfile_datastream(const wchar_t *fname) |
501 | | : filename(), wfilename(fname) |
502 | | { |
503 | | if (wfilename.size() > 0) |
504 | | { |
505 | | struct _stati64 st; |
506 | | if (!_wstati64(wfilename.c_str(), &st)) |
507 | | _fsize = st.st_size; |
508 | | #ifndef WIN32SECURECALLS |
509 | | f = _wfopen(wfilename.c_str(), L"rb"); |
510 | | #else |
511 | | if (_wfopen_s(&f, fname, L"rb")) |
512 | | f = 0; |
513 | | #endif |
514 | | } |
515 | | else |
516 | | { |
517 | | wfilename = std::wstring(); |
518 | | f = 0; |
519 | | } |
520 | | } |
521 | | const wchar_t *LibRaw_bigfile_datastream::wfname() |
522 | | { |
523 | | return wfilename.size() > 0 ? wfilename.c_str() : NULL; |
524 | | } |
525 | | #endif |
526 | | |
527 | | LibRaw_bigfile_datastream::~LibRaw_bigfile_datastream() |
528 | 39.8k | { |
529 | 39.8k | if (f) |
530 | 39.8k | fclose(f); |
531 | 39.8k | } |
532 | 79.7k | int LibRaw_bigfile_datastream::valid() { return f ? 1 : 0; } |
533 | | |
534 | | #define LR_BF_CHK() \ |
535 | 1.01G | do \ |
536 | 1.01G | { \ |
537 | 1.01G | if (!f) \ |
538 | 1.01G | throw LIBRAW_EXCEPTION_IO_EOF; \ |
539 | 1.01G | } while (0) |
540 | | |
541 | | int LibRaw_bigfile_datastream::read(void *ptr, size_t size, size_t nmemb) |
542 | 519M | { |
543 | 519M | LR_BF_CHK(); |
544 | 519M | return int(fread(ptr, size, nmemb, f)); |
545 | 519M | } |
546 | | |
547 | | int LibRaw_bigfile_datastream::eof() |
548 | 5.93M | { |
549 | 5.93M | LR_BF_CHK(); |
550 | 5.93M | return feof(f); |
551 | 5.93M | } |
552 | | |
553 | | int LibRaw_bigfile_datastream::seek(INT64 o, int whence) |
554 | 193M | { |
555 | 193M | LR_BF_CHK(); |
556 | | #if defined(_WIN32) |
557 | | #ifdef WIN32SECURECALLS |
558 | | return _fseeki64(f, o, whence); |
559 | | #else |
560 | | return fseek(f, (long)o, whence); |
561 | | #endif |
562 | | #elif (defined(__ANDROID__) && __ANDROID_API__ < 24) |
563 | | return fseek(f, o, whence); |
564 | | #else |
565 | 193M | return fseeko(f, o, whence); |
566 | 193M | #endif |
567 | 193M | } |
568 | | |
569 | | INT64 LibRaw_bigfile_datastream::tell() |
570 | 296M | { |
571 | 296M | LR_BF_CHK(); |
572 | | #if defined(_WIN32) |
573 | | #ifdef WIN32SECURECALLS |
574 | | return _ftelli64(f); |
575 | | #else |
576 | | return ftell(f); |
577 | | #endif |
578 | | #elif (defined(__ANDROID__) && __ANDROID_API__ < 24) |
579 | | return ftell(f); |
580 | | #else |
581 | 296M | return ftello(f); |
582 | 296M | #endif |
583 | 296M | } |
584 | | |
585 | | char *LibRaw_bigfile_datastream::gets(char *str, int sz) |
586 | 184k | { |
587 | 184k | if(sz<1) return NULL; |
588 | 183k | LR_BF_CHK(); |
589 | 183k | return fgets(str, sz, f); |
590 | 183k | } |
591 | | |
592 | | int LibRaw_bigfile_datastream::scanf_one(const char *fmt, void *val) |
593 | 7.95k | { |
594 | 7.95k | LR_BF_CHK(); |
595 | 7.95k | return |
596 | 7.95k | #ifndef WIN32SECURECALLS |
597 | 7.95k | fscanf(f, fmt, val) |
598 | | #else |
599 | | fscanf_s(f, fmt, val) |
600 | | #endif |
601 | 7.95k | ; |
602 | 7.95k | } |
603 | | |
604 | | const char *LibRaw_bigfile_datastream::fname() |
605 | 3.72k | { |
606 | 3.72k | return filename.size() > 0 ? filename.c_str() : NULL; |
607 | 3.72k | } |
608 | | |
609 | | // == LibRaw_windows_datastream |
610 | | #ifdef LIBRAW_WIN32_CALLS |
611 | | |
612 | | LibRaw_windows_datastream::LibRaw_windows_datastream(const TCHAR *sFile) |
613 | | : LibRaw_buffer_datastream(NULL, 0), hMap_(0), pView_(NULL) |
614 | | { |
615 | | #if defined(WINAPI_FAMILY) && defined(WINAPI_FAMILY_APP) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) |
616 | | HANDLE hFile = CreateFile2(sFile, GENERIC_READ, 0, OPEN_EXISTING, 0); |
617 | | #else |
618 | | HANDLE hFile = CreateFile(sFile, GENERIC_READ, 0, 0, OPEN_EXISTING, |
619 | | FILE_ATTRIBUTE_NORMAL, 0); |
620 | | #endif |
621 | | if (hFile == INVALID_HANDLE_VALUE) |
622 | | throw std::runtime_error("failed to open the file"); |
623 | | |
624 | | try |
625 | | { |
626 | | Open(hFile); |
627 | | } |
628 | | catch (...) |
629 | | { |
630 | | CloseHandle(hFile); |
631 | | throw; |
632 | | } |
633 | | |
634 | | CloseHandle(hFile); // windows will defer the actual closing of this handle |
635 | | // until the hMap_ is closed |
636 | | reconstruct_base(); |
637 | | } |
638 | | |
639 | | // ctor: construct with a file handle - caller is responsible for closing the |
640 | | // file handle |
641 | | LibRaw_windows_datastream::LibRaw_windows_datastream(HANDLE hFile) |
642 | | : LibRaw_buffer_datastream(NULL, 0), hMap_(0), pView_(NULL) |
643 | | { |
644 | | Open(hFile); |
645 | | reconstruct_base(); |
646 | | } |
647 | | |
648 | | // dtor: unmap and close the mapping handle |
649 | | LibRaw_windows_datastream::~LibRaw_windows_datastream() |
650 | | { |
651 | | if (pView_ != NULL) |
652 | | ::UnmapViewOfFile(pView_); |
653 | | |
654 | | if (hMap_ != 0) |
655 | | ::CloseHandle(hMap_); |
656 | | } |
657 | | |
658 | | void LibRaw_windows_datastream::Open(HANDLE hFile) |
659 | | { |
660 | | // create a file mapping handle on the file handle |
661 | | hMap_ = ::CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, 0); |
662 | | if (hMap_ == NULL) |
663 | | throw std::runtime_error("failed to create file mapping"); |
664 | | |
665 | | // now map the whole file base view |
666 | | if (!::GetFileSizeEx(hFile, (PLARGE_INTEGER)&cbView_)) |
667 | | throw std::runtime_error("failed to get the file size"); |
668 | | |
669 | | pView_ = ::MapViewOfFile(hMap_, FILE_MAP_READ, 0, 0, (size_t)cbView_); |
670 | | if (pView_ == NULL) |
671 | | throw std::runtime_error("failed to map the file"); |
672 | | } |
673 | | |
674 | | #endif |
675 | | |
676 | | #if defined (LIBRAW_NO_IOSTREAMS_DATASTREAM) && defined (LIBRAW_WIN32_CALLS) |
677 | | |
678 | | /* LibRaw_bigfile_buffered_datastream: copypasted from LibRaw_bigfile_datastream + extra cache on read */ |
679 | | |
680 | | #undef LR_BF_CHK |
681 | | #define LR_BF_CHK() \ |
682 | | do \ |
683 | | { \ |
684 | | if (fhandle ==0 || fhandle == INVALID_HANDLE_VALUE) \ |
685 | | throw LIBRAW_EXCEPTION_IO_EOF; \ |
686 | | } while (0) |
687 | | |
688 | | #define LIBRAW_BUFFER_ALIGN 4096 |
689 | | |
690 | | int LibRaw_bufio_params::bufsize = 16384; |
691 | | |
692 | | void LibRaw_bufio_params::set_bufsize(int bs) |
693 | | { |
694 | | if (bs > 0) |
695 | | bufsize = bs; |
696 | | } |
697 | | |
698 | | |
699 | | LibRaw_bigfile_buffered_datastream::LibRaw_bigfile_buffered_datastream(const char *fname) |
700 | | : filename(fname), _fsize(0), _fpos(0) |
701 | | #ifdef LIBRAW_WIN32_UNICODEPATHS |
702 | | , wfilename() |
703 | | #endif |
704 | | , iobuffers(), buffered(1) |
705 | | { |
706 | | if (filename.size() > 0) |
707 | | { |
708 | | std::string fn(fname); |
709 | | std::wstring fpath(fn.begin(), fn.end()); |
710 | | #if defined(WINAPI_FAMILY) && defined(WINAPI_FAMILY_APP) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) |
711 | | if ((fhandle = CreateFile2(fpath.c_str(), GENERIC_READ, 0, OPEN_EXISTING, 0)) != INVALID_HANDLE_VALUE) |
712 | | #else |
713 | | if ((fhandle = CreateFileW(fpath.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, |
714 | | OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) |
715 | | #endif |
716 | | { |
717 | | LARGE_INTEGER fs; |
718 | | if (GetFileSizeEx(fhandle, &fs)) |
719 | | _fsize = fs.QuadPart; |
720 | | } |
721 | | } |
722 | | else |
723 | | { |
724 | | filename = std::string(); |
725 | | fhandle = INVALID_HANDLE_VALUE; |
726 | | } |
727 | | } |
728 | | |
729 | | #ifdef LIBRAW_WIN32_UNICODEPATHS |
730 | | LibRaw_bigfile_buffered_datastream::LibRaw_bigfile_buffered_datastream(const wchar_t *fname) |
731 | | : filename(), _fsize(0), _fpos(0), |
732 | | wfilename(fname), iobuffers(), buffered(1) |
733 | | { |
734 | | if (wfilename.size() > 0) |
735 | | { |
736 | | #if defined(WINAPI_FAMILY) && defined(WINAPI_FAMILY_APP) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) |
737 | | if ((fhandle = CreateFile2(wfilename.c_str(), GENERIC_READ, 0, OPEN_EXISTING, 0)) != INVALID_HANDLE_VALUE) |
738 | | #else |
739 | | if ((fhandle = CreateFileW(wfilename.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, |
740 | | OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) |
741 | | #endif |
742 | | { |
743 | | LARGE_INTEGER fs; |
744 | | if (GetFileSizeEx(fhandle, &fs)) |
745 | | _fsize = fs.QuadPart; |
746 | | } |
747 | | |
748 | | } |
749 | | else |
750 | | { |
751 | | wfilename = std::wstring(); |
752 | | fhandle = INVALID_HANDLE_VALUE; |
753 | | } |
754 | | } |
755 | | |
756 | | const wchar_t *LibRaw_bigfile_buffered_datastream::wfname() |
757 | | { |
758 | | return wfilename.size() > 0 ? wfilename.c_str() : NULL; |
759 | | } |
760 | | #endif |
761 | | |
762 | | LibRaw_bigfile_buffered_datastream::~LibRaw_bigfile_buffered_datastream() |
763 | | { |
764 | | if (valid()) |
765 | | CloseHandle(fhandle); |
766 | | } |
767 | | int LibRaw_bigfile_buffered_datastream::valid() { |
768 | | return (fhandle != NULL) && (fhandle != INVALID_HANDLE_VALUE); |
769 | | } |
770 | | |
771 | | const char *LibRaw_bigfile_buffered_datastream::fname() |
772 | | { |
773 | | return filename.size() > 0 ? filename.c_str() : NULL; |
774 | | } |
775 | | |
776 | | |
777 | | INT64 LibRaw_bigfile_buffered_datastream::readAt(void *ptr, size_t size, INT64 off) |
778 | | { |
779 | | LR_BF_CHK(); |
780 | | DWORD NumberOfBytesRead; |
781 | | DWORD nNumberOfBytesToRead = (DWORD)size; |
782 | | struct _OVERLAPPED olap; |
783 | | memset(&olap, 0, sizeof(olap)); |
784 | | olap.Offset = off & 0xffffffff; |
785 | | olap.OffsetHigh = off >> 32; |
786 | | if (ReadFile(fhandle, ptr, nNumberOfBytesToRead, &NumberOfBytesRead, &olap)) |
787 | | return NumberOfBytesRead; |
788 | | else if (NumberOfBytesRead > 0) |
789 | | return NumberOfBytesRead; |
790 | | else |
791 | | return 0; |
792 | | } |
793 | | |
794 | | #define MAX(a, b) ((a) > (b) ? (a) : (b)) |
795 | | #define MIN(a, b) ((a) < (b) ? (a) : (b)) |
796 | | |
797 | | #ifdef _MSC_VER |
798 | | #pragma intrinsic(memcpy) |
799 | | #endif |
800 | | |
801 | | int LibRaw_bigfile_buffered_datastream::read(void *data, size_t size, size_t nmemb) |
802 | | { |
803 | | if (size < 1 || nmemb < 1) |
804 | | return 0; |
805 | | LR_BF_CHK(); |
806 | | INT64 count = size * nmemb; |
807 | | INT64 partbytes = 0; |
808 | | if (!buffered) |
809 | | { |
810 | | INT64 r = readAt(data, count, _fpos); |
811 | | _fpos += r; |
812 | | return int(r / size); |
813 | | } |
814 | | |
815 | | unsigned char *fBuffer = (unsigned char*)iobuffers[0].data(); |
816 | | while (count) |
817 | | { |
818 | | INT64 inbuffer = 0; |
819 | | // See if the request is totally inside buffer. |
820 | | if (iobuffers[0].contains(_fpos, inbuffer)) |
821 | | { |
822 | | if (inbuffer >= count) |
823 | | { |
824 | | memcpy(data, fBuffer + (unsigned)(_fpos - iobuffers[0]._bstart), count); |
825 | | _fpos += count; |
826 | | return int((count + partbytes) / size); |
827 | | } |
828 | | memcpy(data, fBuffer + (_fpos - iobuffers[0]._bstart), inbuffer); |
829 | | partbytes += inbuffer; |
830 | | count -= inbuffer; |
831 | | data = (void *)(((char *)data) + inbuffer); |
832 | | _fpos += inbuffer; |
833 | | } |
834 | | if (count > (INT64) iobuffers[0].size()) |
835 | | { |
836 | | fallback: |
837 | | if (_fpos + count > _fsize) |
838 | | count = MAX(0, _fsize - _fpos); |
839 | | if (count > 0) |
840 | | { |
841 | | INT64 r = readAt(data, count, _fpos); |
842 | | _fpos += r; |
843 | | return int((r + partbytes) / size); |
844 | | } |
845 | | else |
846 | | return 0; |
847 | | } |
848 | | |
849 | | if (!fillBufferAt(0, _fpos)) |
850 | | goto fallback; |
851 | | } |
852 | | return 0; |
853 | | } |
854 | | |
855 | | bool LibRaw_bigfile_buffered_datastream::fillBufferAt(int bi, INT64 off) |
856 | | { |
857 | | if (off < 0LL) return false; |
858 | | iobuffers[bi]._bstart = off; |
859 | | if (iobuffers[bi].size() >= LIBRAW_BUFFER_ALIGN * 2)// Align to a file block. |
860 | | iobuffers[bi]._bstart &= (INT64)~((INT64)(LIBRAW_BUFFER_ALIGN - 1)); |
861 | | |
862 | | iobuffers[bi]._bend = MIN(iobuffers[bi]._bstart + (INT64)iobuffers[bi].size(), _fsize); |
863 | | if (iobuffers[bi]._bend <= off) // Buffer alignment problem, fallback |
864 | | return false; |
865 | | INT64 rr = readAt(iobuffers[bi].data(), (uint32_t)(iobuffers[bi]._bend - iobuffers[bi]._bstart), iobuffers[bi]._bstart); |
866 | | if (rr > 0) |
867 | | { |
868 | | iobuffers[bi]._bend = iobuffers[bi]._bstart + rr; |
869 | | return true; |
870 | | } |
871 | | return false; |
872 | | } |
873 | | |
874 | | |
875 | | int LibRaw_bigfile_buffered_datastream::eof() |
876 | | { |
877 | | LR_BF_CHK(); |
878 | | return _fpos >= _fsize; |
879 | | } |
880 | | |
881 | | int LibRaw_bigfile_buffered_datastream::seek(INT64 o, int whence) |
882 | | { |
883 | | LR_BF_CHK(); |
884 | | if (whence == SEEK_SET) _fpos = o; |
885 | | else if (whence == SEEK_END) _fpos = o > 0 ? _fsize : _fsize + o; |
886 | | else if (whence == SEEK_CUR) _fpos += o; |
887 | | return 0; |
888 | | } |
889 | | |
890 | | INT64 LibRaw_bigfile_buffered_datastream::tell() |
891 | | { |
892 | | LR_BF_CHK(); |
893 | | return _fpos; |
894 | | } |
895 | | |
896 | | char *LibRaw_bigfile_buffered_datastream::gets(char *s, int sz) |
897 | | { |
898 | | if (sz < 1) |
899 | | return NULL; |
900 | | else if (sz < 2) |
901 | | { |
902 | | s[0] = 0; |
903 | | return s; |
904 | | } |
905 | | |
906 | | LR_BF_CHK(); |
907 | | INT64 contains; |
908 | | int bufindex = selectStringBuffer(sz, contains); |
909 | | if (bufindex < 0) return NULL; |
910 | | if (contains >= sz) |
911 | | { |
912 | | unsigned char *buf = iobuffers[bufindex].data() + (_fpos - iobuffers[bufindex]._bstart); |
913 | | INT64 streampos = 0; |
914 | | INT64 streamsize = contains; |
915 | | unsigned char *str = (unsigned char *)s; |
916 | | unsigned char *psrc, *pdest; |
917 | | psrc = buf + streampos; |
918 | | pdest = str; |
919 | | |
920 | | while ((INT64(psrc - buf) < streamsize) && ((pdest - str) < INT64(sz)-1)) // sz-1: to append \0 |
921 | | { |
922 | | *pdest = *psrc; |
923 | | if (*psrc == '\n') |
924 | | break; |
925 | | psrc++; |
926 | | pdest++; |
927 | | } |
928 | | if (INT64(psrc - buf) < streamsize) |
929 | | psrc++; |
930 | | if ((pdest - str) < sz - 1) |
931 | | *(++pdest) = 0; |
932 | | else |
933 | | s[sz - 1] = 0; // ensure trailing zero |
934 | | streampos = psrc - buf; |
935 | | _fpos += streampos; |
936 | | return s; |
937 | | } |
938 | | return NULL; |
939 | | } |
940 | | |
941 | | int LibRaw_bigfile_buffered_datastream::selectStringBuffer(INT64 len, INT64& contains) |
942 | | { |
943 | | if (iobuffers[0].contains(_fpos, contains) && contains >= len) |
944 | | return 0; |
945 | | |
946 | | if (iobuffers[1].contains(_fpos, contains) && contains >= len) |
947 | | return 1; |
948 | | |
949 | | fillBufferAt(1, _fpos); |
950 | | if (iobuffers[1].contains(_fpos, contains) && contains >= len) |
951 | | return 1; |
952 | | return -1; |
953 | | } |
954 | | |
955 | | int LibRaw_bigfile_buffered_datastream::scanf_one(const char *fmt, void *val) |
956 | | { |
957 | | LR_BF_CHK(); |
958 | | INT64 contains = 0; |
959 | | int bufindex = selectStringBuffer(24, contains); |
960 | | if (bufindex < 0) return -1; |
961 | | if (contains >= 24) |
962 | | { |
963 | | unsigned char *bstart = iobuffers[bufindex].data() + (_fpos - iobuffers[bufindex]._bstart); |
964 | | INT64 streampos = 0; |
965 | | INT64 streamsize = contains; |
966 | | int |
967 | | #ifndef WIN32SECURECALLS |
968 | | scanf_res = sscanf((char *)(bstart), fmt, val); |
969 | | #else |
970 | | scanf_res = sscanf_s((char *)(bstart), fmt, val); |
971 | | #endif |
972 | | if (scanf_res > 0) |
973 | | { |
974 | | int xcnt = 0; |
975 | | while (streampos < streamsize) |
976 | | { |
977 | | streampos++; |
978 | | xcnt++; |
979 | | if (bstart[streampos] == 0 || bstart[streampos] == ' ' || |
980 | | bstart[streampos] == '\t' || bstart[streampos] == '\n' || xcnt > 24) |
981 | | break; |
982 | | } |
983 | | _fpos += streampos; |
984 | | return scanf_res; |
985 | | } |
986 | | } |
987 | | return -1; |
988 | | } |
989 | | |
990 | | #endif |
991 | | |