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