1 /* -*- C++ -*-
2 * File: libraw_datastream.cpp
3 * Copyright 2008-2018 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_types.h"
27 #include "libraw/libraw.h"
28 #include "libraw/libraw_datastream.h"
29 #include <sys/stat.h>
30 #ifdef USE_JASPER
31 #include <jasper/jasper.h> /* Decode RED camera movies */
32 #else
33 #define NO_JASPER
34 #endif
35 #ifdef USE_JPEG
36 #include <jpeglib.h>
37 #else
38 #define NO_JPEG
39 #endif
40
tempbuffer_open(void * buf,size_t size)41 int LibRaw_abstract_datastream::tempbuffer_open(void *buf, size_t size)
42 {
43 if (substream)
44 return EBUSY;
45 substream = new LibRaw_buffer_datastream(buf, size);
46 return substream ? 0 : EINVAL;
47 }
48
tempbuffer_close()49 void LibRaw_abstract_datastream::tempbuffer_close()
50 {
51 if (substream)
52 delete substream;
53 substream = NULL;
54 }
55
56 // == LibRaw_file_datastream ==
57
~LibRaw_file_datastream()58 LibRaw_file_datastream::~LibRaw_file_datastream()
59 {
60 if (jas_file)
61 fclose(jas_file);
62 }
63
LibRaw_file_datastream(const char * fname)64 LibRaw_file_datastream::LibRaw_file_datastream(const char *fname)
65 : filename(fname), _fsize(0)
66 #ifdef WIN32
67 ,
68 wfilename()
69 #endif
70 ,
71 jas_file(NULL)
72 {
73 if (filename.size() > 0)
74 {
75 #ifndef WIN32
76 struct stat st;
77 if (!stat(filename.c_str(), &st))
78 _fsize = st.st_size;
79 #else
80 struct _stati64 st;
81 if (!_stati64(filename.c_str(), &st))
82 _fsize = st.st_size;
83 #endif
84
85 std::auto_ptr<std::filebuf> buf(new std::filebuf());
86 buf->open(filename.c_str(), std::ios_base::in | std::ios_base::binary);
87 if (buf->is_open())
88 {
89 f = buf;
90 }
91 }
92 }
93 #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310)
LibRaw_file_datastream(const wchar_t * fname)94 LibRaw_file_datastream::LibRaw_file_datastream(const wchar_t *fname)
95 : filename(), wfilename(fname), jas_file(NULL), _fsize(0)
96 {
97 if (wfilename.size() > 0)
98 {
99 struct _stati64 st;
100 if (!_wstati64(wfilename.c_str(), &st))
101 _fsize = st.st_size;
102 std::auto_ptr<std::filebuf> buf(new std::filebuf());
103 buf->open(wfilename.c_str(), std::ios_base::in | std::ios_base::binary);
104 if (buf->is_open())
105 {
106 f = buf;
107 }
108 }
109 }
wfname()110 const wchar_t *LibRaw_file_datastream::wfname() { return wfilename.size() > 0 ? wfilename.c_str() : NULL; }
111 #endif
112
valid()113 int LibRaw_file_datastream::valid() { return f.get() ? 1 : 0; }
114
115 #define LR_STREAM_CHK() \
116 do \
117 { \
118 if (!f.get()) \
119 throw LIBRAW_EXCEPTION_IO_EOF; \
120 } while (0)
121
read(void * ptr,size_t size,size_t nmemb)122 int LibRaw_file_datastream::read(void *ptr, size_t size, size_t nmemb)
123 {
124 if (substream)
125 return substream->read(ptr, size, nmemb);
126
127 /* Visual Studio 2008 marks sgetn as insecure, but VS2010 does not. */
128 #if defined(WIN32SECURECALLS) && (_MSC_VER < 1600)
129 LR_STREAM_CHK();
130 return int(f->_Sgetn_s(static_cast<char *>(ptr), nmemb * size, nmemb * size) / (size > 0 ? size : 1));
131 #else
132 LR_STREAM_CHK();
133 return int(f->sgetn(static_cast<char *>(ptr), std::streamsize(nmemb * size)) / (size > 0 ? size : 1));
134 #endif
135 }
136
eof()137 int LibRaw_file_datastream::eof()
138 {
139 if (substream)
140 return substream->eof();
141 LR_STREAM_CHK();
142 return f->sgetc() == EOF;
143 }
144
seek(INT64 o,int whence)145 int LibRaw_file_datastream::seek(INT64 o, int whence)
146 {
147 if (substream)
148 return substream->seek(o, whence);
149 LR_STREAM_CHK();
150 std::ios_base::seekdir dir;
151 switch (whence)
152 {
153 case SEEK_SET:
154 dir = std::ios_base::beg;
155 break;
156 case SEEK_CUR:
157 dir = std::ios_base::cur;
158 break;
159 case SEEK_END:
160 dir = std::ios_base::end;
161 break;
162 default:
163 dir = std::ios_base::beg;
164 }
165 return f->pubseekoff((long)o, dir) < 0;
166 }
167
tell()168 INT64 LibRaw_file_datastream::tell()
169 {
170 if (substream)
171 return substream->tell();
172 LR_STREAM_CHK();
173 return f->pubseekoff(0, std::ios_base::cur);
174 }
175
gets(char * str,int sz)176 char *LibRaw_file_datastream::gets(char *str, int sz)
177 {
178 if (substream)
179 return substream->gets(str, sz);
180 LR_STREAM_CHK();
181 std::istream is(f.get());
182 is.getline(str, sz);
183 if (is.fail())
184 return 0;
185 return str;
186 }
187
scanf_one(const char * fmt,void * val)188 int LibRaw_file_datastream::scanf_one(const char *fmt, void *val)
189 {
190 if (substream)
191 return substream->scanf_one(fmt, val);
192 LR_STREAM_CHK();
193
194 std::istream is(f.get());
195
196 /* HUGE ASSUMPTION: *fmt is either "%d" or "%f" */
197 if (strcmp(fmt, "%d") == 0)
198 {
199 int d;
200 is >> d;
201 if (is.fail())
202 return EOF;
203 *(static_cast<int *>(val)) = d;
204 }
205 else
206 {
207 float f;
208 is >> f;
209 if (is.fail())
210 return EOF;
211 *(static_cast<float *>(val)) = f;
212 }
213
214 return 1;
215 }
216
fname()217 const char *LibRaw_file_datastream::fname() { return filename.size() > 0 ? filename.c_str() : NULL; }
218
219 /* You can't have a "subfile" and a "tempfile" at the same time. */
subfile_open(const char * fn)220 int LibRaw_file_datastream::subfile_open(const char *fn)
221 {
222 LR_STREAM_CHK();
223 if (saved_f.get())
224 return EBUSY;
225 saved_f = f;
226 std::auto_ptr<std::filebuf> buf(new std::filebuf());
227
228 buf->open(fn, std::ios_base::in | std::ios_base::binary);
229 if (!buf->is_open())
230 {
231 f = saved_f;
232 return ENOENT;
233 }
234 else
235 {
236 f = buf;
237 }
238
239 return 0;
240 }
241
242 #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310)
subfile_open(const wchar_t * fn)243 int LibRaw_file_datastream::subfile_open(const wchar_t *fn)
244 {
245 LR_STREAM_CHK();
246 if (saved_f.get())
247 return EBUSY;
248 saved_f = f;
249 std::auto_ptr<std::filebuf> buf(new std::filebuf());
250
251 buf->open(fn, std::ios_base::in | std::ios_base::binary);
252 if (!buf->is_open())
253 {
254 f = saved_f;
255 return ENOENT;
256 }
257 else
258 {
259 f = buf;
260 }
261
262 return 0;
263 }
264 #endif
265
subfile_close()266 void LibRaw_file_datastream::subfile_close()
267 {
268 if (!saved_f.get())
269 return;
270 f = saved_f;
271 }
272
273 #undef LR_STREAM_CHK
274
make_jas_stream()275 void *LibRaw_file_datastream::make_jas_stream()
276 {
277 #ifdef NO_JASPER
278 return NULL;
279 #else
280 #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310)
281 if (wfname())
282 {
283 jas_file = _wfopen(wfname(), L"rb");
284 return jas_stream_fdopen(fileno(jas_file), "rb");
285 }
286 else
287 #endif
288 {
289 return jas_stream_fopen(fname(), "rb");
290 }
291 #endif
292 }
293
jpeg_src(void * jpegdata)294 int LibRaw_file_datastream::jpeg_src(void *jpegdata)
295 {
296 #ifdef NO_JPEG
297 return -1; // not supported
298 #else
299 if (jas_file)
300 {
301 fclose(jas_file);
302 jas_file = NULL;
303 }
304 #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310)
305 if (wfname())
306 {
307 jas_file = _wfopen(wfname(), L"rb");
308 }
309 else
310 #endif
311 {
312 jas_file = fopen(fname(), "rb");
313 }
314 if (jas_file)
315 {
316 fseek(jas_file, tell(), SEEK_SET);
317 j_decompress_ptr cinfo = (j_decompress_ptr)jpegdata;
318 jpeg_stdio_src(cinfo, jas_file);
319 return 0; // OK
320 }
321 return -1;
322 #endif
323 }
324
325 // == LibRaw_buffer_datastream
LibRaw_buffer_datastream(void * buffer,size_t bsize)326 LibRaw_buffer_datastream::LibRaw_buffer_datastream(void *buffer, size_t bsize)
327 {
328 buf = (unsigned char *)buffer;
329 streampos = 0;
330 streamsize = bsize;
331 }
332
~LibRaw_buffer_datastream()333 LibRaw_buffer_datastream::~LibRaw_buffer_datastream() {}
334
read(void * ptr,size_t sz,size_t nmemb)335 int LibRaw_buffer_datastream::read(void *ptr, size_t sz, size_t nmemb)
336 {
337 if (substream)
338 return substream->read(ptr, sz, nmemb);
339 size_t to_read = sz * nmemb;
340 if (to_read > streamsize - streampos)
341 to_read = streamsize - streampos;
342 if (to_read < 1)
343 return 0;
344 memmove(ptr, buf + streampos, to_read);
345 streampos += to_read;
346 return int((to_read + sz - 1) / (sz > 0 ? sz : 1));
347 }
348
seek(INT64 o,int whence)349 int LibRaw_buffer_datastream::seek(INT64 o, int whence)
350 {
351 if (substream)
352 return substream->seek(o, whence);
353 switch (whence)
354 {
355 case SEEK_SET:
356 if (o < 0)
357 streampos = 0;
358 else if (size_t(o) > streamsize)
359 streampos = streamsize;
360 else
361 streampos = size_t(o);
362 return 0;
363 case SEEK_CUR:
364 if (o < 0)
365 {
366 if (size_t(-o) >= streampos)
367 streampos = 0;
368 else
369 streampos += (size_t)o;
370 }
371 else if (o > 0)
372 {
373 if (o + streampos > streamsize)
374 streampos = streamsize;
375 else
376 streampos += (size_t)o;
377 }
378 return 0;
379 case SEEK_END:
380 if (o > 0)
381 streampos = streamsize;
382 else if (size_t(-o) > streamsize)
383 streampos = 0;
384 else
385 streampos = streamsize + (size_t)o;
386 return 0;
387 default:
388 return 0;
389 }
390 }
391
tell()392 INT64 LibRaw_buffer_datastream::tell()
393 {
394 if (substream)
395 return substream->tell();
396 return INT64(streampos);
397 }
398
gets(char * s,int sz)399 char *LibRaw_buffer_datastream::gets(char *s, int sz)
400 {
401 if (substream)
402 return substream->gets(s, sz);
403 unsigned char *psrc, *pdest, *str;
404 str = (unsigned char *)s;
405 psrc = buf + streampos;
406 pdest = str;
407 while ((size_t(psrc - buf) < streamsize) && ((pdest - str) < sz))
408 {
409 *pdest = *psrc;
410 if (*psrc == '\n')
411 break;
412 psrc++;
413 pdest++;
414 }
415 if (size_t(psrc - buf) < streamsize)
416 psrc++;
417 if ((pdest - str) < sz)
418 *(++pdest) = 0;
419 streampos = psrc - buf;
420 return s;
421 }
422
scanf_one(const char * fmt,void * val)423 int LibRaw_buffer_datastream::scanf_one(const char *fmt, void *val)
424 {
425 if (substream)
426 return substream->scanf_one(fmt, val);
427 int scanf_res;
428 if (streampos > streamsize)
429 return 0;
430 #ifndef WIN32SECURECALLS
431 scanf_res = sscanf((char *)(buf + streampos), fmt, val);
432 #else
433 scanf_res = sscanf_s((char *)(buf + streampos), fmt, val);
434 #endif
435 if (scanf_res > 0)
436 {
437 int xcnt = 0;
438 while (streampos < streamsize)
439 {
440 streampos++;
441 xcnt++;
442 if (buf[streampos] == 0 || buf[streampos] == ' ' || buf[streampos] == '\t' || buf[streampos] == '\n' || xcnt > 24)
443 break;
444 }
445 }
446 return scanf_res;
447 }
448
eof()449 int LibRaw_buffer_datastream::eof()
450 {
451 if (substream)
452 return substream->eof();
453 return streampos >= streamsize;
454 }
valid()455 int LibRaw_buffer_datastream::valid() { return buf ? 1 : 0; }
456
make_jas_stream()457 void *LibRaw_buffer_datastream::make_jas_stream()
458 {
459 #ifdef NO_JASPER
460 return NULL;
461 #else
462 return jas_stream_memopen((char *)buf + streampos, streamsize - streampos);
463 #endif
464 }
465
jpeg_src(void * jpegdata)466 int LibRaw_buffer_datastream::jpeg_src(void *jpegdata)
467 {
468 #if defined(NO_JPEG) || !defined(USE_JPEG)
469 return -1;
470 #else
471 j_decompress_ptr cinfo = (j_decompress_ptr)jpegdata;
472 jpeg_mem_src(cinfo, (unsigned char *)buf + streampos, streamsize - streampos);
473 return 0;
474 #endif
475 }
476
477 // int LibRaw_buffer_datastream
478
479 // == LibRaw_bigfile_datastream
LibRaw_bigfile_datastream(const char * fname)480 LibRaw_bigfile_datastream::LibRaw_bigfile_datastream(const char *fname)
481 : filename(fname)
482 #ifdef WIN32
483 ,
484 wfilename()
485 #endif
486 {
487 if (filename.size() > 0)
488 {
489 #ifndef WIN32
490 struct stat st;
491 if (!stat(filename.c_str(), &st))
492 _fsize = st.st_size;
493 #else
494 struct _stati64 st;
495 if (!_stati64(filename.c_str(), &st))
496 _fsize = st.st_size;
497 #endif
498
499 #ifndef WIN32SECURECALLS
500 f = fopen(fname, "rb");
501 #else
502 if (fopen_s(&f, fname, "rb"))
503 f = 0;
504 #endif
505 }
506 else
507 {
508 filename = std::string();
509 f = 0;
510 }
511 sav = 0;
512 }
513
514 #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310)
LibRaw_bigfile_datastream(const wchar_t * fname)515 LibRaw_bigfile_datastream::LibRaw_bigfile_datastream(const wchar_t *fname) : filename(), wfilename(fname)
516 {
517 if (wfilename.size() > 0)
518 {
519 struct _stati64 st;
520 if (!_wstati64(wfilename.c_str(), &st))
521 _fsize = st.st_size;
522 #ifndef WIN32SECURECALLS
523 f = _wfopen(wfilename.c_str(), L"rb");
524 #else
525 if (_wfopen_s(&f, fname, L"rb"))
526 f = 0;
527 #endif
528 }
529 else
530 {
531 wfilename = std::wstring();
532 f = 0;
533 }
534 sav = 0;
535 }
wfname()536 const wchar_t *LibRaw_bigfile_datastream::wfname() { return wfilename.size() > 0 ? wfilename.c_str() : NULL; }
537 #endif
538
~LibRaw_bigfile_datastream()539 LibRaw_bigfile_datastream::~LibRaw_bigfile_datastream()
540 {
541 if (f)
542 fclose(f);
543 if (sav)
544 fclose(sav);
545 }
valid()546 int LibRaw_bigfile_datastream::valid() { return f ? 1 : 0; }
547
548 #define LR_BF_CHK() \
549 do \
550 { \
551 if (!f) \
552 throw LIBRAW_EXCEPTION_IO_EOF; \
553 } while (0)
554
read(void * ptr,size_t size,size_t nmemb)555 int LibRaw_bigfile_datastream::read(void *ptr, size_t size, size_t nmemb)
556 {
557 LR_BF_CHK();
558 return substream ? substream->read(ptr, size, nmemb) : int(fread(ptr, size, nmemb, f));
559 }
560
eof()561 int LibRaw_bigfile_datastream::eof()
562 {
563 LR_BF_CHK();
564 return substream ? substream->eof() : feof(f);
565 }
566
seek(INT64 o,int whence)567 int LibRaw_bigfile_datastream::seek(INT64 o, int whence)
568 {
569 LR_BF_CHK();
570 #if defined(WIN32)
571 #ifdef WIN32SECURECALLS
572 return substream ? substream->seek(o, whence) : _fseeki64(f, o, whence);
573 #else
574 return substream ? substream->seek(o, whence) : fseek(f, (long)o, whence);
575 #endif
576 #else
577 return substream ? substream->seek(o, whence) : fseeko(f, o, whence);
578 #endif
579 }
580
tell()581 INT64 LibRaw_bigfile_datastream::tell()
582 {
583 LR_BF_CHK();
584 #if defined(WIN32)
585 #ifdef WIN32SECURECALLS
586 return substream ? substream->tell() : _ftelli64(f);
587 #else
588 return substream ? substream->tell() : ftell(f);
589 #endif
590 #else
591 return substream ? substream->tell() : ftello(f);
592 #endif
593 }
594
gets(char * str,int sz)595 char *LibRaw_bigfile_datastream::gets(char *str, int sz)
596 {
597 LR_BF_CHK();
598 return substream ? substream->gets(str, sz) : fgets(str, sz, f);
599 }
600
scanf_one(const char * fmt,void * val)601 int LibRaw_bigfile_datastream::scanf_one(const char *fmt, void *val)
602 {
603 LR_BF_CHK();
604 return substream ? substream->scanf_one(fmt, val) :
605 #ifndef WIN32SECURECALLS
606 fscanf(f, fmt, val)
607 #else
608 fscanf_s(f, fmt, val)
609 #endif
610 ;
611 }
612
fname()613 const char *LibRaw_bigfile_datastream::fname() { return filename.size() > 0 ? filename.c_str() : NULL; }
614
subfile_open(const char * fn)615 int LibRaw_bigfile_datastream::subfile_open(const char *fn)
616 {
617 if (sav)
618 return EBUSY;
619 sav = f;
620 #ifndef WIN32SECURECALLS
621 f = fopen(fn, "rb");
622 #else
623 fopen_s(&f, fn, "rb");
624 #endif
625 if (!f)
626 {
627 f = sav;
628 sav = NULL;
629 return ENOENT;
630 }
631 else
632 return 0;
633 }
634 #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310)
subfile_open(const wchar_t * fn)635 int LibRaw_bigfile_datastream::subfile_open(const wchar_t *fn)
636 {
637 if (sav)
638 return EBUSY;
639 sav = f;
640 #ifndef WIN32SECURECALLS
641 f = _wfopen(fn, L"rb");
642 #else
643 _wfopen_s(&f, fn, L"rb");
644 #endif
645 if (!f)
646 {
647 f = sav;
648 sav = NULL;
649 return ENOENT;
650 }
651 else
652 return 0;
653 }
654 #endif
655
subfile_close()656 void LibRaw_bigfile_datastream::subfile_close()
657 {
658 if (!sav)
659 return;
660 fclose(f);
661 f = sav;
662 sav = 0;
663 }
664
make_jas_stream()665 void *LibRaw_bigfile_datastream::make_jas_stream()
666 {
667 #ifdef NO_JASPER
668 return NULL;
669 #else
670 return jas_stream_fdopen(fileno(f), "rb");
671 #endif
672 }
673
jpeg_src(void * jpegdata)674 int LibRaw_bigfile_datastream::jpeg_src(void *jpegdata)
675 {
676 #ifdef NO_JPEG
677 return -1;
678 #else
679 if (!f)
680 return -1;
681 j_decompress_ptr cinfo = (j_decompress_ptr)jpegdata;
682 jpeg_stdio_src(cinfo, f);
683 return 0; // OK
684 #endif
685 }
686
687 // == LibRaw_windows_datastream
688 #ifdef WIN32
689
LibRaw_windows_datastream(const TCHAR * sFile)690 LibRaw_windows_datastream::LibRaw_windows_datastream(const TCHAR *sFile)
691 : LibRaw_buffer_datastream(NULL, 0), hMap_(0), pView_(NULL)
692 {
693 HANDLE hFile = CreateFile(sFile, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
694 if (hFile == INVALID_HANDLE_VALUE)
695 throw std::runtime_error("failed to open the file");
696
697 try
698 {
699 Open(hFile);
700 }
701 catch (...)
702 {
703 CloseHandle(hFile);
704 throw;
705 }
706
707 CloseHandle(hFile); // windows will defer the actual closing of this handle until the hMap_ is closed
708 reconstruct_base();
709 }
710
711 // ctor: construct with a file handle - caller is responsible for closing the file handle
LibRaw_windows_datastream(HANDLE hFile)712 LibRaw_windows_datastream::LibRaw_windows_datastream(HANDLE hFile)
713 : LibRaw_buffer_datastream(NULL, 0), hMap_(0), pView_(NULL)
714 {
715 Open(hFile);
716 reconstruct_base();
717 }
718
719 // dtor: unmap and close the mapping handle
~LibRaw_windows_datastream()720 LibRaw_windows_datastream::~LibRaw_windows_datastream()
721 {
722 if (pView_ != NULL)
723 ::UnmapViewOfFile(pView_);
724
725 if (hMap_ != 0)
726 ::CloseHandle(hMap_);
727 }
728
Open(HANDLE hFile)729 void LibRaw_windows_datastream::Open(HANDLE hFile)
730 {
731 // create a file mapping handle on the file handle
732 hMap_ = ::CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, 0);
733 if (hMap_ == NULL)
734 throw std::runtime_error("failed to create file mapping");
735
736 // now map the whole file base view
737 if (!::GetFileSizeEx(hFile, (PLARGE_INTEGER)&cbView_))
738 throw std::runtime_error("failed to get the file size");
739
740 pView_ = ::MapViewOfFile(hMap_, FILE_MAP_READ, 0, 0, (size_t)cbView_);
741 if (pView_ == NULL)
742 throw std::runtime_error("failed to map the file");
743 }
744
745 #endif
746