Coverage Report

Created: 2026-07-20 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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