| /* -*- C++ -*- |
| * File: libraw_datastream.cpp |
| * Copyright 2008-2025 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 <stdexcept> |
| #endif |
| #endif |
| |
| #define LIBRAW_LIBRARY_BUILD |
| #include "third_party/libraw/libraw/libraw.h" |
| #include "third_party/libraw/libraw/libraw_types.h" |
| #include "third_party/libraw/libraw/libraw_datastream.h" |
| #include <sys/stat.h> |
| #ifdef USE_JPEG |
| #include <jpeglib.h> |
| #include <jerror.h> |
| #else |
| #define NO_JPEG |
| #endif |
| |
| #ifdef USE_JPEG |
| |
| typedef struct |
| { |
| struct jpeg_source_mgr pub; /* public fields */ |
| LibRaw_abstract_datastream *instream; /* source stream */ |
| JOCTET *buffer; /* start of buffer */ |
| boolean start_of_file; /* have we gotten any data yet? */ |
| } lr_jpg_source_mgr; |
| |
| typedef lr_jpg_source_mgr *lr_jpg_src_ptr; |
| |
| #define LR_JPEG_INPUT_BUF_SIZE 16384 |
| |
| static void f_init_source(j_decompress_ptr cinfo) |
| { |
| lr_jpg_src_ptr src = (lr_jpg_src_ptr)cinfo->src; |
| src->start_of_file = TRUE; |
| } |
| |
| #ifdef ERREXIT |
| #undef ERREXIT |
| #endif |
| |
| #define ERREXIT(cinfo, code) \ |
| ((cinfo)->err->msg_code = (code), \ |
| (*(cinfo)->err->error_exit)((j_common_ptr)(cinfo))) |
| |
| static boolean lr_fill_input_buffer(j_decompress_ptr cinfo) |
| { |
| lr_jpg_src_ptr src = (lr_jpg_src_ptr)cinfo->src; |
| size_t nbytes; |
| |
| nbytes = src->instream->read((void*)src->buffer, 1, LR_JPEG_INPUT_BUF_SIZE); |
| |
| if (nbytes <= 0) |
| { |
| if (src->start_of_file) /* Treat empty input file as fatal error */ |
| ERREXIT(cinfo, JERR_INPUT_EMPTY); |
| WARNMS(cinfo, JWRN_JPEG_EOF); |
| /* Insert a fake EOI marker */ |
| src->buffer[0] = (JOCTET)0xFF; |
| src->buffer[1] = (JOCTET)JPEG_EOI; |
| nbytes = 2; |
| } |
| |
| src->pub.next_input_byte = src->buffer; |
| src->pub.bytes_in_buffer = nbytes; |
| src->start_of_file = FALSE; |
| return TRUE; |
| } |
| |
| static void lr_skip_input_data(j_decompress_ptr cinfo, long num_bytes) |
| { |
| struct jpeg_source_mgr *src = cinfo->src; |
| if (num_bytes > 0) |
| { |
| while (num_bytes > (long)src->bytes_in_buffer) |
| { |
| num_bytes -= (long)src->bytes_in_buffer; |
| (void)(*src->fill_input_buffer)(cinfo); |
| /* note we assume that fill_input_buffer will never return FALSE, |
| * so suspension need not be handled. |
| */ |
| } |
| src->next_input_byte += (size_t)num_bytes; |
| src->bytes_in_buffer -= (size_t)num_bytes; |
| } |
| } |
| |
| static void lr_term_source(j_decompress_ptr /*cinfo*/) {} |
| |
| static void lr_jpeg_src(j_decompress_ptr cinfo, LibRaw_abstract_datastream *inf) |
| { |
| lr_jpg_src_ptr src; |
| if (cinfo->src == NULL) |
| { /* first time for this JPEG object? */ |
| cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small)( |
| (j_common_ptr)cinfo, JPOOL_PERMANENT, sizeof(lr_jpg_source_mgr)); |
| src = (lr_jpg_src_ptr)cinfo->src; |
| src->buffer = (JOCTET *)(*cinfo->mem->alloc_small)( |
| (j_common_ptr)cinfo, JPOOL_PERMANENT, |
| LR_JPEG_INPUT_BUF_SIZE * sizeof(JOCTET)); |
| } |
| else if (cinfo->src->init_source != f_init_source) |
| { |
| ERREXIT(cinfo, JERR_BUFFER_SIZE); |
| } |
| |
| src = (lr_jpg_src_ptr)cinfo->src; |
| src->pub.init_source = f_init_source; |
| src->pub.fill_input_buffer = lr_fill_input_buffer; |
| src->pub.skip_input_data = lr_skip_input_data; |
| src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ |
| src->pub.term_source = lr_term_source; |
| src->instream = inf; |
| src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ |
| src->pub.next_input_byte = NULL; /* until buffer loaded */ |
| } |
| #endif |
| |
| int LibRaw_abstract_datastream::jpeg_src(void *jpegdata) |
| { |
| #ifdef NO_JPEG |
| return -1; |
| #else |
| j_decompress_ptr cinfo = (j_decompress_ptr)jpegdata; |
| buffering_off(); |
| lr_jpeg_src(cinfo, this); |
| return 0; // OK |
| #endif |
| } |
| |
| |
| #ifndef LIBRAW_NO_IOSTREAMS_DATASTREAM |
| // == LibRaw_file_datastream == |
| |
| LibRaw_file_datastream::LibRaw_file_datastream(const char *fname) |
| : filename(fname), _fsize(0) |
| #ifdef LIBRAW_WIN32_UNICODEPATHS |
| , |
| wfilename() |
| #endif |
| { |
| if (filename.size() > 0) |
| { |
| #ifndef LIBRAW_WIN32_CALLS |
| 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 |
| #ifdef LIBRAW_USE_AUTOPTR |
| std::auto_ptr<std::filebuf> buf(new std::filebuf()); |
| #else |
| std::unique_ptr<std::filebuf> buf(new std::filebuf()); |
| #endif |
| buf->open(filename.c_str(), std::ios_base::in | std::ios_base::binary); |
| if (buf->is_open()) |
| { |
| #ifdef LIBRAW_USE_AUTOPTR |
| f = buf; |
| #else |
| f = std::move(buf); |
| #endif |
| } |
| } |
| } |
| #ifdef LIBRAW_WIN32_UNICODEPATHS |
| LibRaw_file_datastream::LibRaw_file_datastream(const wchar_t *fname) |
| : filename(), wfilename(fname), _fsize(0) |
| { |
| if (wfilename.size() > 0) |
| { |
| struct _stati64 st; |
| if (!_wstati64(wfilename.c_str(), &st)) |
| _fsize = st.st_size; |
| #ifdef LIBRAW_USE_AUTOPTR |
| std::auto_ptr<std::filebuf> buf(new std::filebuf()); |
| #else |
| std::unique_ptr<std::filebuf> buf(new std::filebuf()); |
| #endif |
| buf->open(wfilename.c_str(), std::ios_base::in | std::ios_base::binary); |
| if (buf->is_open()) |
| { |
| #ifdef LIBRAW_USE_AUTOPTR |
| f = buf; |
| #else |
| f = std::move(buf); |
| #endif |
| } |
| } |
| } |
| 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) |
| { |
| /* 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<char *>(ptr), nmemb * size, nmemb * size) / |
| (size > 0 ? size : 1)); |
| #else |
| LR_STREAM_CHK(); |
| return int(f->sgetn(static_cast<char *>(ptr), std::streamsize(nmemb * size)) / |
| (size > 0 ? size : 1)); |
| #endif |
| } |
| |
| int LibRaw_file_datastream::eof() |
| { |
| LR_STREAM_CHK(); |
| return f->sgetc() == EOF; |
| } |
| |
| int LibRaw_file_datastream::seek(INT64 o, int 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() |
| { |
| LR_STREAM_CHK(); |
| return f->pubseekoff(0, std::ios_base::cur); |
| } |
| |
| char *LibRaw_file_datastream::gets(char *str, int sz) |
| { |
| if(sz<1) return NULL; |
| 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) |
| { |
| 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<int *>(val)) = d; |
| } |
| else |
| { |
| float f; |
| is >> f; |
| if (is.fail()) |
| return EOF; |
| *(static_cast<float *>(val)) = f; |
| } |
| |
| return 1; |
| } |
| |
| const char *LibRaw_file_datastream::fname() |
| { |
| return filename.size() > 0 ? filename.c_str() : NULL; |
| } |
| |
| #undef LR_STREAM_CHK |
| |
| #endif |
| |
| // == LibRaw_buffer_datastream |
| LibRaw_buffer_datastream::LibRaw_buffer_datastream(const 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) |
| { |
| 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) |
| { |
| 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() |
| { |
| return INT64(streampos); |
| } |
| |
| char *LibRaw_buffer_datastream::gets(char *s, int sz) |
| { |
| if(sz<1) return NULL; |
| unsigned char *psrc, *pdest, *str; |
| str = (unsigned char *)s; |
| psrc = buf + streampos; |
| pdest = str; |
| if(streampos >= streamsize) return NULL; |
| while ((size_t(psrc - buf) < streamsize) && ((pdest - str) < (sz-1))) |
| { |
| *pdest = *psrc; |
| if (*psrc == '\n') |
| break; |
| psrc++; |
| pdest++; |
| } |
| if (size_t(psrc - buf) < streamsize) |
| psrc++; |
| if ((pdest - str) < sz-1) { |
| // We broke from the while loop early, pdest is currently pointing to the |
| // first '\n' character. |
| if (size_t(psrc - buf) < streamsize) pdest++; |
| *pdest = 0; |
| } else { |
| s[sz - 1] = 0; // ensure trailing zero |
| } |
| |
| streampos = psrc - buf; |
| return s; |
| } |
| |
| int LibRaw_buffer_datastream::scanf_one(const char *fmt, void *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-1) |
| { |
| 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() |
| { |
| return streampos >= streamsize; |
| } |
| int LibRaw_buffer_datastream::valid() { return buf ? 1 : 0; } |
| |
| |
| 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,(unsigned long)(streamsize - streampos)); |
| return 0; |
| #endif |
| } |
| |
| // int LibRaw_buffer_datastream |
| |
| // == LibRaw_bigfile_datastream |
| LibRaw_bigfile_datastream::LibRaw_bigfile_datastream(const char *fname) |
| : filename(fname) |
| #ifdef LIBRAW_WIN32_UNICODEPATHS |
| , |
| wfilename() |
| #endif |
| { |
| if (filename.size() > 0) |
| { |
| #ifndef LIBRAW_WIN32_CALLS |
| 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; |
| } |
| } |
| |
| #ifdef LIBRAW_WIN32_UNICODEPATHS |
| 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; |
| } |
| } |
| 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); |
| } |
| 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 int(fread(ptr, size, nmemb, f)); |
| } |
| |
| int LibRaw_bigfile_datastream::eof() |
| { |
| LR_BF_CHK(); |
| return feof(f); |
| } |
| |
| int LibRaw_bigfile_datastream::seek(INT64 o, int whence) |
| { |
| LR_BF_CHK(); |
| #if defined(_WIN32) |
| #ifdef WIN32SECURECALLS |
| return _fseeki64(f, o, whence); |
| #else |
| return fseek(f, (long)o, whence); |
| #endif |
| #elif (defined(__ANDROID__) && __ANDROID_API__ < 24) |
| return fseek(f, o, whence); |
| #else |
| return fseeko(f, o, whence); |
| #endif |
| } |
| |
| INT64 LibRaw_bigfile_datastream::tell() |
| { |
| LR_BF_CHK(); |
| #if defined(_WIN32) |
| #ifdef WIN32SECURECALLS |
| return _ftelli64(f); |
| #else |
| return ftell(f); |
| #endif |
| #elif (defined(__ANDROID__) && __ANDROID_API__ < 24) |
| return ftell(f); |
| #else |
| return ftello(f); |
| #endif |
| } |
| |
| char *LibRaw_bigfile_datastream::gets(char *str, int sz) |
| { |
| if(sz<1) return NULL; |
| LR_BF_CHK(); |
| return fgets(str, sz, f); |
| } |
| |
| int LibRaw_bigfile_datastream::scanf_one(const char *fmt, void *val) |
| { |
| LR_BF_CHK(); |
| return |
| #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; |
| } |
| |
| // == LibRaw_windows_datastream |
| #ifdef LIBRAW_WIN32_CALLS |
| |
| LibRaw_windows_datastream::LibRaw_windows_datastream(const TCHAR *sFile) |
| : LibRaw_buffer_datastream(NULL, 0), hMap_(0), pView_(NULL) |
| { |
| #if defined(WINAPI_FAMILY) && defined(WINAPI_FAMILY_APP) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) |
| HANDLE hFile = CreateFile2(sFile, GENERIC_READ, 0, OPEN_EXISTING, 0); |
| #else |
| HANDLE hFile = CreateFile(sFile, GENERIC_READ, 0, 0, OPEN_EXISTING, |
| FILE_ATTRIBUTE_NORMAL, 0); |
| #endif |
| 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 |
| |
| #if defined (LIBRAW_NO_IOSTREAMS_DATASTREAM) && defined (LIBRAW_WIN32_CALLS) |
| |
| /* LibRaw_bigfile_buffered_datastream: copypasted from LibRaw_bigfile_datastream + extra cache on read */ |
| |
| #undef LR_BF_CHK |
| #define LR_BF_CHK() \ |
| do \ |
| { \ |
| if (fhandle ==0 || fhandle == INVALID_HANDLE_VALUE) \ |
| throw LIBRAW_EXCEPTION_IO_EOF; \ |
| } while (0) |
| |
| #define LIBRAW_BUFFER_ALIGN 4096 |
| |
| int LibRaw_bufio_params::bufsize = 16384; |
| |
| void LibRaw_bufio_params::set_bufsize(int bs) |
| { |
| if (bs > 0) |
| bufsize = bs; |
| } |
| |
| |
| LibRaw_bigfile_buffered_datastream::LibRaw_bigfile_buffered_datastream(const char *fname) |
| : filename(fname), _fsize(0), _fpos(0) |
| #ifdef LIBRAW_WIN32_UNICODEPATHS |
| , wfilename() |
| #endif |
| , iobuffers(), buffered(1) |
| { |
| if (filename.size() > 0) |
| { |
| std::string fn(fname); |
| std::wstring fpath(fn.begin(), fn.end()); |
| #if defined(WINAPI_FAMILY) && defined(WINAPI_FAMILY_APP) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) |
| if ((fhandle = CreateFile2(fpath.c_str(), GENERIC_READ, 0, OPEN_EXISTING, 0)) != INVALID_HANDLE_VALUE) |
| #else |
| if ((fhandle = CreateFileW(fpath.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, |
| OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) |
| #endif |
| { |
| LARGE_INTEGER fs; |
| if (GetFileSizeEx(fhandle, &fs)) |
| _fsize = fs.QuadPart; |
| } |
| } |
| else |
| { |
| filename = std::string(); |
| fhandle = INVALID_HANDLE_VALUE; |
| } |
| } |
| |
| #ifdef LIBRAW_WIN32_UNICODEPATHS |
| LibRaw_bigfile_buffered_datastream::LibRaw_bigfile_buffered_datastream(const wchar_t *fname) |
| : filename(), _fsize(0), _fpos(0), |
| wfilename(fname), iobuffers(), buffered(1) |
| { |
| if (wfilename.size() > 0) |
| { |
| #if defined(WINAPI_FAMILY) && defined(WINAPI_FAMILY_APP) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) |
| if ((fhandle = CreateFile2(wfilename.c_str(), GENERIC_READ, 0, OPEN_EXISTING, 0)) != INVALID_HANDLE_VALUE) |
| #else |
| if ((fhandle = CreateFileW(wfilename.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, |
| OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) |
| #endif |
| { |
| LARGE_INTEGER fs; |
| if (GetFileSizeEx(fhandle, &fs)) |
| _fsize = fs.QuadPart; |
| } |
| |
| } |
| else |
| { |
| wfilename = std::wstring(); |
| fhandle = INVALID_HANDLE_VALUE; |
| } |
| } |
| |
| const wchar_t *LibRaw_bigfile_buffered_datastream::wfname() |
| { |
| return wfilename.size() > 0 ? wfilename.c_str() : NULL; |
| } |
| #endif |
| |
| LibRaw_bigfile_buffered_datastream::~LibRaw_bigfile_buffered_datastream() |
| { |
| if (valid()) |
| CloseHandle(fhandle); |
| } |
| int LibRaw_bigfile_buffered_datastream::valid() { |
| return (fhandle != NULL) && (fhandle != INVALID_HANDLE_VALUE); |
| } |
| |
| const char *LibRaw_bigfile_buffered_datastream::fname() |
| { |
| return filename.size() > 0 ? filename.c_str() : NULL; |
| } |
| |
| |
| INT64 LibRaw_bigfile_buffered_datastream::readAt(void *ptr, size_t size, INT64 off) |
| { |
| LR_BF_CHK(); |
| DWORD NumberOfBytesRead; |
| DWORD nNumberOfBytesToRead = (DWORD)size; |
| struct _OVERLAPPED olap; |
| memset(&olap, 0, sizeof(olap)); |
| olap.Offset = off & 0xffffffff; |
| olap.OffsetHigh = off >> 32; |
| if (ReadFile(fhandle, ptr, nNumberOfBytesToRead, &NumberOfBytesRead, &olap)) |
| return NumberOfBytesRead; |
| else if (NumberOfBytesRead > 0) |
| return NumberOfBytesRead; |
| else |
| return 0; |
| } |
| |
| #define MAX(a, b) ((a) > (b) ? (a) : (b)) |
| #define MIN(a, b) ((a) < (b) ? (a) : (b)) |
| |
| #ifdef _MSC_VER |
| #pragma intrinsic(memcpy) |
| #endif |
| |
| int LibRaw_bigfile_buffered_datastream::read(void *data, size_t size, size_t nmemb) |
| { |
| if (size < 1 || nmemb < 1) |
| return 0; |
| LR_BF_CHK(); |
| INT64 count = size * nmemb; |
| INT64 partbytes = 0; |
| if (!buffered) |
| { |
| INT64 r = readAt(data, count, _fpos); |
| _fpos += r; |
| return int(r / size); |
| } |
| |
| unsigned char *fBuffer = (unsigned char*)iobuffers[0].data(); |
| while (count) |
| { |
| INT64 inbuffer = 0; |
| // See if the request is totally inside buffer. |
| if (iobuffers[0].contains(_fpos, inbuffer)) |
| { |
| if (inbuffer >= count) |
| { |
| memcpy(data, fBuffer + (unsigned)(_fpos - iobuffers[0]._bstart), count); |
| _fpos += count; |
| return int((count + partbytes) / size); |
| } |
| memcpy(data, fBuffer + (_fpos - iobuffers[0]._bstart), inbuffer); |
| partbytes += inbuffer; |
| count -= inbuffer; |
| data = (void *)(((char *)data) + inbuffer); |
| _fpos += inbuffer; |
| } |
| if (count > (INT64) iobuffers[0].size()) |
| { |
| fallback: |
| if (_fpos + count > _fsize) |
| count = MAX(0, _fsize - _fpos); |
| if (count > 0) |
| { |
| INT64 r = readAt(data, count, _fpos); |
| _fpos += r; |
| return int((r + partbytes) / size); |
| } |
| else |
| return 0; |
| } |
| |
| if (!fillBufferAt(0, _fpos)) |
| goto fallback; |
| } |
| return 0; |
| } |
| |
| bool LibRaw_bigfile_buffered_datastream::fillBufferAt(int bi, INT64 off) |
| { |
| if (off < 0LL) return false; |
| iobuffers[bi]._bstart = off; |
| if (iobuffers[bi].size() >= LIBRAW_BUFFER_ALIGN * 2)// Align to a file block. |
| iobuffers[bi]._bstart &= (INT64)~((INT64)(LIBRAW_BUFFER_ALIGN - 1)); |
| |
| iobuffers[bi]._bend = MIN(iobuffers[bi]._bstart + (INT64)iobuffers[bi].size(), _fsize); |
| if (iobuffers[bi]._bend <= off) // Buffer alignment problem, fallback |
| return false; |
| INT64 rr = readAt(iobuffers[bi].data(), (uint32_t)(iobuffers[bi]._bend - iobuffers[bi]._bstart), iobuffers[bi]._bstart); |
| if (rr > 0) |
| { |
| iobuffers[bi]._bend = iobuffers[bi]._bstart + rr; |
| return true; |
| } |
| return false; |
| } |
| |
| |
| int LibRaw_bigfile_buffered_datastream::eof() |
| { |
| LR_BF_CHK(); |
| return _fpos >= _fsize; |
| } |
| |
| int LibRaw_bigfile_buffered_datastream::seek(INT64 o, int whence) |
| { |
| LR_BF_CHK(); |
| if (whence == SEEK_SET) _fpos = o; |
| else if (whence == SEEK_END) _fpos = o > 0 ? _fsize : _fsize + o; |
| else if (whence == SEEK_CUR) _fpos += o; |
| return 0; |
| } |
| |
| INT64 LibRaw_bigfile_buffered_datastream::tell() |
| { |
| LR_BF_CHK(); |
| return _fpos; |
| } |
| |
| char *LibRaw_bigfile_buffered_datastream::gets(char *s, int sz) |
| { |
| if (sz < 1) |
| return NULL; |
| else if (sz < 2) |
| { |
| s[0] = 0; |
| return s; |
| } |
| |
| LR_BF_CHK(); |
| INT64 contains; |
| int bufindex = selectStringBuffer(sz, contains); |
| if (bufindex < 0) return NULL; |
| if (contains >= sz) |
| { |
| unsigned char *buf = iobuffers[bufindex].data() + (_fpos - iobuffers[bufindex]._bstart); |
| INT64 streampos = 0; |
| INT64 streamsize = contains; |
| unsigned char *str = (unsigned char *)s; |
| unsigned char *psrc, *pdest; |
| psrc = buf + streampos; |
| pdest = str; |
| |
| while ((INT64(psrc - buf) < streamsize) && ((pdest - str) < INT64(sz)-1)) // sz-1: to append \0 |
| { |
| *pdest = *psrc; |
| if (*psrc == '\n') |
| break; |
| psrc++; |
| pdest++; |
| } |
| if (INT64(psrc - buf) < streamsize) |
| psrc++; |
| if ((pdest - str) < sz - 1) |
| *(++pdest) = 0; |
| else |
| s[sz - 1] = 0; // ensure trailing zero |
| streampos = psrc - buf; |
| _fpos += streampos; |
| return s; |
| } |
| return NULL; |
| } |
| |
| int LibRaw_bigfile_buffered_datastream::selectStringBuffer(INT64 len, INT64& contains) |
| { |
| if (iobuffers[0].contains(_fpos, contains) && contains >= len) |
| return 0; |
| |
| if (iobuffers[1].contains(_fpos, contains) && contains >= len) |
| return 1; |
| |
| fillBufferAt(1, _fpos); |
| if (iobuffers[1].contains(_fpos, contains) && contains >= len) |
| return 1; |
| return -1; |
| } |
| |
| int LibRaw_bigfile_buffered_datastream::scanf_one(const char *fmt, void *val) |
| { |
| LR_BF_CHK(); |
| INT64 contains = 0; |
| int bufindex = selectStringBuffer(24, contains); |
| if (bufindex < 0) return -1; |
| if (contains >= 24) |
| { |
| unsigned char *bstart = iobuffers[bufindex].data() + (_fpos - iobuffers[bufindex]._bstart); |
| INT64 streampos = 0; |
| INT64 streamsize = contains; |
| int |
| #ifndef WIN32SECURECALLS |
| scanf_res = sscanf((char *)(bstart), fmt, val); |
| #else |
| scanf_res = sscanf_s((char *)(bstart), fmt, val); |
| #endif |
| if (scanf_res > 0) |
| { |
| int xcnt = 0; |
| while (streampos < streamsize) |
| { |
| streampos++; |
| xcnt++; |
| if (bstart[streampos] == 0 || bstart[streampos] == ' ' || |
| bstart[streampos] == '\t' || bstart[streampos] == '\n' || xcnt > 24) |
| break; |
| } |
| _fpos += streampos; |
| return scanf_res; |
| } |
| } |
| return -1; |
| } |
| |
| #endif |
| |