/* -*- C++ -*- * File: libraw_datastream.cpp * Copyright 2008-2018 LibRaw LLC (info@libraw.org) * * LibRaw C++ interface (implementation) LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). */ #ifdef WIN32 #ifdef __MINGW32__ #define _WIN32_WINNT 0x0500 #include #endif #endif #define LIBRAW_LIBRARY_BUILD #include "libraw/libraw_types.h" #include "libraw/libraw.h" #include "libraw/libraw_datastream.h" #include #ifdef USE_JASPER #include /* Decode RED camera movies */ #else #define NO_JASPER #endif #ifdef USE_JPEG #include #else #define NO_JPEG #endif int LibRaw_abstract_datastream::tempbuffer_open(void *buf, size_t size) { if (substream) return EBUSY; substream = new LibRaw_buffer_datastream(buf, size); return substream ? 0 : EINVAL; } void LibRaw_abstract_datastream::tempbuffer_close() { if (substream) delete substream; substream = NULL; } // == LibRaw_file_datastream == LibRaw_file_datastream::~LibRaw_file_datastream() { if (jas_file) fclose(jas_file); } LibRaw_file_datastream::LibRaw_file_datastream(const char *fname) : filename(fname), _fsize(0) #ifdef WIN32 , wfilename() #endif , jas_file(NULL) { if (filename.size() > 0) { #ifndef WIN32 struct stat st; if (!stat(filename.c_str(), &st)) _fsize = st.st_size; #else struct _stati64 st; if (!_stati64(filename.c_str(), &st)) _fsize = st.st_size; #endif std::auto_ptr buf(new std::filebuf()); buf->open(filename.c_str(), std::ios_base::in | std::ios_base::binary); if (buf->is_open()) { f = buf; } } } #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) LibRaw_file_datastream::LibRaw_file_datastream(const wchar_t *fname) : filename(), wfilename(fname), jas_file(NULL), _fsize(0) { if (wfilename.size() > 0) { struct _stati64 st; if (!_wstati64(wfilename.c_str(), &st)) _fsize = st.st_size; std::auto_ptr buf(new std::filebuf()); buf->open(wfilename.c_str(), std::ios_base::in | std::ios_base::binary); if (buf->is_open()) { f = buf; } } } const wchar_t *LibRaw_file_datastream::wfname() { return wfilename.size() > 0 ? wfilename.c_str() : NULL; } #endif int LibRaw_file_datastream::valid() { return f.get() ? 1 : 0; } #define LR_STREAM_CHK() \ do \ { \ if (!f.get()) \ throw LIBRAW_EXCEPTION_IO_EOF; \ } while (0) int LibRaw_file_datastream::read(void *ptr, size_t size, size_t nmemb) { if (substream) return substream->read(ptr, size, nmemb); /* Visual Studio 2008 marks sgetn as insecure, but VS2010 does not. */ #if defined(WIN32SECURECALLS) && (_MSC_VER < 1600) LR_STREAM_CHK(); return int(f->_Sgetn_s(static_cast(ptr), nmemb * size, nmemb * size) / (size > 0 ? size : 1)); #else LR_STREAM_CHK(); return int(f->sgetn(static_cast(ptr), std::streamsize(nmemb * size)) / (size > 0 ? size : 1)); #endif } int LibRaw_file_datastream::eof() { if (substream) return substream->eof(); LR_STREAM_CHK(); return f->sgetc() == EOF; } int LibRaw_file_datastream::seek(INT64 o, int whence) { if (substream) return substream->seek(o, whence); LR_STREAM_CHK(); std::ios_base::seekdir dir; switch (whence) { case SEEK_SET: dir = std::ios_base::beg; break; case SEEK_CUR: dir = std::ios_base::cur; break; case SEEK_END: dir = std::ios_base::end; break; default: dir = std::ios_base::beg; } return f->pubseekoff((long)o, dir) < 0; } INT64 LibRaw_file_datastream::tell() { if (substream) return substream->tell(); LR_STREAM_CHK(); return f->pubseekoff(0, std::ios_base::cur); } char *LibRaw_file_datastream::gets(char *str, int sz) { if (substream) return substream->gets(str, sz); LR_STREAM_CHK(); std::istream is(f.get()); is.getline(str, sz); if (is.fail()) return 0; return str; } int LibRaw_file_datastream::scanf_one(const char *fmt, void *val) { if (substream) return substream->scanf_one(fmt, val); LR_STREAM_CHK(); std::istream is(f.get()); /* HUGE ASSUMPTION: *fmt is either "%d" or "%f" */ if (strcmp(fmt, "%d") == 0) { int d; is >> d; if (is.fail()) return EOF; *(static_cast(val)) = d; } else { float f; is >> f; if (is.fail()) return EOF; *(static_cast(val)) = f; } return 1; } const char *LibRaw_file_datastream::fname() { return filename.size() > 0 ? filename.c_str() : NULL; } /* You can't have a "subfile" and a "tempfile" at the same time. */ int LibRaw_file_datastream::subfile_open(const char *fn) { LR_STREAM_CHK(); if (saved_f.get()) return EBUSY; saved_f = f; std::auto_ptr buf(new std::filebuf()); buf->open(fn, std::ios_base::in | std::ios_base::binary); if (!buf->is_open()) { f = saved_f; return ENOENT; } else { f = buf; } return 0; } #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) int LibRaw_file_datastream::subfile_open(const wchar_t *fn) { LR_STREAM_CHK(); if (saved_f.get()) return EBUSY; saved_f = f; std::auto_ptr buf(new std::filebuf()); buf->open(fn, std::ios_base::in | std::ios_base::binary); if (!buf->is_open()) { f = saved_f; return ENOENT; } else { f = buf; } return 0; } #endif void LibRaw_file_datastream::subfile_close() { if (!saved_f.get()) return; f = saved_f; } #undef LR_STREAM_CHK void *LibRaw_file_datastream::make_jas_stream() { #ifdef NO_JASPER return NULL; #else #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) if (wfname()) { jas_file = _wfopen(wfname(), L"rb"); return jas_stream_fdopen(fileno(jas_file), "rb"); } else #endif { return jas_stream_fopen(fname(), "rb"); } #endif } int LibRaw_file_datastream::jpeg_src(void *jpegdata) { #ifdef NO_JPEG return -1; // not supported #else if (jas_file) { fclose(jas_file); jas_file = NULL; } #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) if (wfname()) { jas_file = _wfopen(wfname(), L"rb"); } else #endif { jas_file = fopen(fname(), "rb"); } if (jas_file) { fseek(jas_file, tell(), SEEK_SET); j_decompress_ptr cinfo = (j_decompress_ptr)jpegdata; jpeg_stdio_src(cinfo, jas_file); return 0; // OK } return -1; #endif } // == LibRaw_buffer_datastream LibRaw_buffer_datastream::LibRaw_buffer_datastream(void *buffer, size_t bsize) { buf = (unsigned char *)buffer; streampos = 0; streamsize = bsize; } LibRaw_buffer_datastream::~LibRaw_buffer_datastream() {} int LibRaw_buffer_datastream::read(void *ptr, size_t sz, size_t nmemb) { if (substream) return substream->read(ptr, sz, nmemb); size_t to_read = sz * nmemb; if (to_read > streamsize - streampos) to_read = streamsize - streampos; if (to_read < 1) return 0; memmove(ptr, buf + streampos, to_read); streampos += to_read; return int((to_read + sz - 1) / (sz > 0 ? sz : 1)); } int LibRaw_buffer_datastream::seek(INT64 o, int whence) { if (substream) return substream->seek(o, whence); switch (whence) { case SEEK_SET: if (o < 0) streampos = 0; else if (size_t(o) > streamsize) streampos = streamsize; else streampos = size_t(o); return 0; case SEEK_CUR: if (o < 0) { if (size_t(-o) >= streampos) streampos = 0; else streampos += (size_t)o; } else if (o > 0) { if (o + streampos > streamsize) streampos = streamsize; else streampos += (size_t)o; } return 0; case SEEK_END: if (o > 0) streampos = streamsize; else if (size_t(-o) > streamsize) streampos = 0; else streampos = streamsize + (size_t)o; return 0; default: return 0; } } INT64 LibRaw_buffer_datastream::tell() { if (substream) return substream->tell(); return INT64(streampos); } char *LibRaw_buffer_datastream::gets(char *s, int sz) { if (substream) return substream->gets(s, sz); unsigned char *psrc, *pdest, *str; str = (unsigned char *)s; psrc = buf + streampos; pdest = str; while ((size_t(psrc - buf) < streamsize) && ((pdest - str) < sz)) { *pdest = *psrc; if (*psrc == '\n') break; psrc++; pdest++; } if (size_t(psrc - buf) < streamsize) psrc++; if ((pdest - str) < sz) *(++pdest) = 0; streampos = psrc - buf; return s; } int LibRaw_buffer_datastream::scanf_one(const char *fmt, void *val) { if (substream) return substream->scanf_one(fmt, val); int scanf_res; if (streampos > streamsize) return 0; #ifndef WIN32SECURECALLS scanf_res = sscanf((char *)(buf + streampos), fmt, val); #else scanf_res = sscanf_s((char *)(buf + streampos), fmt, val); #endif if (scanf_res > 0) { int xcnt = 0; while (streampos < streamsize) { streampos++; xcnt++; if (buf[streampos] == 0 || buf[streampos] == ' ' || buf[streampos] == '\t' || buf[streampos] == '\n' || xcnt > 24) break; } } return scanf_res; } int LibRaw_buffer_datastream::eof() { if (substream) return substream->eof(); return streampos >= streamsize; } int LibRaw_buffer_datastream::valid() { return buf ? 1 : 0; } void *LibRaw_buffer_datastream::make_jas_stream() { #ifdef NO_JASPER return NULL; #else return jas_stream_memopen((char *)buf + streampos, streamsize - streampos); #endif } int LibRaw_buffer_datastream::jpeg_src(void *jpegdata) { #if defined(NO_JPEG) || !defined(USE_JPEG) return -1; #else j_decompress_ptr cinfo = (j_decompress_ptr)jpegdata; jpeg_mem_src(cinfo, (unsigned char *)buf + streampos, streamsize - streampos); return 0; #endif } // int LibRaw_buffer_datastream // == LibRaw_bigfile_datastream LibRaw_bigfile_datastream::LibRaw_bigfile_datastream(const char *fname) : filename(fname) #ifdef WIN32 , wfilename() #endif { if (filename.size() > 0) { #ifndef WIN32 struct stat st; if (!stat(filename.c_str(), &st)) _fsize = st.st_size; #else struct _stati64 st; if (!_stati64(filename.c_str(), &st)) _fsize = st.st_size; #endif #ifndef WIN32SECURECALLS f = fopen(fname, "rb"); #else if (fopen_s(&f, fname, "rb")) f = 0; #endif } else { filename = std::string(); f = 0; } sav = 0; } #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) LibRaw_bigfile_datastream::LibRaw_bigfile_datastream(const wchar_t *fname) : filename(), wfilename(fname) { if (wfilename.size() > 0) { struct _stati64 st; if (!_wstati64(wfilename.c_str(), &st)) _fsize = st.st_size; #ifndef WIN32SECURECALLS f = _wfopen(wfilename.c_str(), L"rb"); #else if (_wfopen_s(&f, fname, L"rb")) f = 0; #endif } else { wfilename = std::wstring(); f = 0; } sav = 0; } const wchar_t *LibRaw_bigfile_datastream::wfname() { return wfilename.size() > 0 ? wfilename.c_str() : NULL; } #endif LibRaw_bigfile_datastream::~LibRaw_bigfile_datastream() { if (f) fclose(f); if (sav) fclose(sav); } int LibRaw_bigfile_datastream::valid() { return f ? 1 : 0; } #define LR_BF_CHK() \ do \ { \ if (!f) \ throw LIBRAW_EXCEPTION_IO_EOF; \ } while (0) int LibRaw_bigfile_datastream::read(void *ptr, size_t size, size_t nmemb) { LR_BF_CHK(); return substream ? substream->read(ptr, size, nmemb) : int(fread(ptr, size, nmemb, f)); } int LibRaw_bigfile_datastream::eof() { LR_BF_CHK(); return substream ? substream->eof() : feof(f); } int LibRaw_bigfile_datastream::seek(INT64 o, int whence) { LR_BF_CHK(); #if defined(WIN32) #ifdef WIN32SECURECALLS return substream ? substream->seek(o, whence) : _fseeki64(f, o, whence); #else return substream ? substream->seek(o, whence) : fseek(f, (long)o, whence); #endif #else return substream ? substream->seek(o, whence) : fseeko(f, o, whence); #endif } INT64 LibRaw_bigfile_datastream::tell() { LR_BF_CHK(); #if defined(WIN32) #ifdef WIN32SECURECALLS return substream ? substream->tell() : _ftelli64(f); #else return substream ? substream->tell() : ftell(f); #endif #else return substream ? substream->tell() : ftello(f); #endif } char *LibRaw_bigfile_datastream::gets(char *str, int sz) { LR_BF_CHK(); return substream ? substream->gets(str, sz) : fgets(str, sz, f); } int LibRaw_bigfile_datastream::scanf_one(const char *fmt, void *val) { LR_BF_CHK(); return substream ? substream->scanf_one(fmt, val) : #ifndef WIN32SECURECALLS fscanf(f, fmt, val) #else fscanf_s(f, fmt, val) #endif ; } const char *LibRaw_bigfile_datastream::fname() { return filename.size() > 0 ? filename.c_str() : NULL; } int LibRaw_bigfile_datastream::subfile_open(const char *fn) { if (sav) return EBUSY; sav = f; #ifndef WIN32SECURECALLS f = fopen(fn, "rb"); #else fopen_s(&f, fn, "rb"); #endif if (!f) { f = sav; sav = NULL; return ENOENT; } else return 0; } #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) int LibRaw_bigfile_datastream::subfile_open(const wchar_t *fn) { if (sav) return EBUSY; sav = f; #ifndef WIN32SECURECALLS f = _wfopen(fn, L"rb"); #else _wfopen_s(&f, fn, L"rb"); #endif if (!f) { f = sav; sav = NULL; return ENOENT; } else return 0; } #endif void LibRaw_bigfile_datastream::subfile_close() { if (!sav) return; fclose(f); f = sav; sav = 0; } void *LibRaw_bigfile_datastream::make_jas_stream() { #ifdef NO_JASPER return NULL; #else return jas_stream_fdopen(fileno(f), "rb"); #endif } int LibRaw_bigfile_datastream::jpeg_src(void *jpegdata) { #ifdef NO_JPEG return -1; #else if (!f) return -1; j_decompress_ptr cinfo = (j_decompress_ptr)jpegdata; jpeg_stdio_src(cinfo, f); return 0; // OK #endif } // == LibRaw_windows_datastream #ifdef WIN32 LibRaw_windows_datastream::LibRaw_windows_datastream(const TCHAR *sFile) : LibRaw_buffer_datastream(NULL, 0), hMap_(0), pView_(NULL) { HANDLE hFile = CreateFile(sFile, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hFile == INVALID_HANDLE_VALUE) throw std::runtime_error("failed to open the file"); try { Open(hFile); } catch (...) { CloseHandle(hFile); throw; } CloseHandle(hFile); // windows will defer the actual closing of this handle until the hMap_ is closed reconstruct_base(); } // ctor: construct with a file handle - caller is responsible for closing the file handle LibRaw_windows_datastream::LibRaw_windows_datastream(HANDLE hFile) : LibRaw_buffer_datastream(NULL, 0), hMap_(0), pView_(NULL) { Open(hFile); reconstruct_base(); } // dtor: unmap and close the mapping handle LibRaw_windows_datastream::~LibRaw_windows_datastream() { if (pView_ != NULL) ::UnmapViewOfFile(pView_); if (hMap_ != 0) ::CloseHandle(hMap_); } void LibRaw_windows_datastream::Open(HANDLE hFile) { // create a file mapping handle on the file handle hMap_ = ::CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, 0); if (hMap_ == NULL) throw std::runtime_error("failed to create file mapping"); // now map the whole file base view if (!::GetFileSizeEx(hFile, (PLARGE_INTEGER)&cbView_)) throw std::runtime_error("failed to get the file size"); pView_ = ::MapViewOfFile(hMap_, FILE_MAP_READ, 0, 0, (size_t)cbView_); if (pView_ == NULL) throw std::runtime_error("failed to map the file"); } #endif