Coverage Report

Created: 2025-10-12 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/alembic/lib/Alembic/Ogawa/IStreams.cpp
Line
Count
Source
1
//-*****************************************************************************
2
//
3
// Copyright (c) 2013,
4
//  Sony Pictures Imageworks Inc. and
5
//  Industrial Light & Magic, a division of Lucasfilm Entertainment Company Ltd.
6
//
7
// All rights reserved.
8
//
9
// Redistribution and use in source and binary forms, with or without
10
// modification, are permitted provided that the following conditions are
11
// met:
12
// *       Redistributions of source code must retain the above copyright
13
// notice, this list of conditions and the following disclaimer.
14
// *       Redistributions in binary form must reproduce the above
15
// copyright notice, this list of conditions and the following disclaimer
16
// in the documentation and/or other materials provided with the
17
// distribution.
18
// *       Neither the name of Industrial Light & Magic nor the names of
19
// its contributors may be used to endorse or promote products derived
20
// from this software without specific prior written permission.
21
//
22
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
//
34
//-*****************************************************************************
35
36
#include <Alembic/Ogawa/IStreams.h>
37
#include <fstream>
38
#include <stdexcept>
39
40
41
#if defined (__unix__) || defined (__HAIKU__) || \
42
    (defined (__APPLE__) && defined (__MACH__))
43
44
    #include <sys/mman.h>
45
    #include <sys/stat.h>
46
    #include <fcntl.h>
47
    #include <unistd.h>
48
    #include <errno.h>
49
    #include <cstring>
50
51
#elif defined(_WIN32)
52
53
    #include <windows.h>
54
    #include <fcntl.h>
55
    #include <io.h>
56
    #include <share.h>
57
    #include <sys/stat.h>
58
59
#else
60
    #error Platform not supported.
61
#endif
62
63
64
65
66
namespace Alembic {
67
namespace Ogawa {
68
namespace ALEMBIC_VERSION_NS
69
{
70
71
namespace
72
{
73
74
class IStreamReader
75
{
76
public:
77
176
    virtual ~IStreamReader() {}
78
79
    virtual std::size_t numStreams() const = 0;
80
81
    virtual bool isOpen() const = 0;
82
83
    virtual bool read(std::size_t iThreadId, Alembic::Util::uint64_t iPos,
84
                      Alembic::Util::uint64_t iSize, void* oBuf) = 0;
85
86
    // not all streams have a size
87
0
    virtual Alembic::Util::uint64_t size() {return 0xffffffffffffffff;};
88
};
89
90
typedef Alembic::Util::shared_ptr<IStreamReader> IStreamReaderPtr;
91
92
93
class StdIStreamReader : public IStreamReader
94
{
95
public:
96
0
    StdIStreamReader(const std::vector<std::istream*>& iStreams) : streams(
97
0
        iStreams)
98
0
    {
99
0
        locks = new Alembic::Util::mutex[streams.size()];
100
101
        // preserve the initial position of these streams
102
0
        offsets.reserve(streams.size());
103
0
        for (size_t i = 0; i < streams.size(); i++)
104
0
        {
105
0
            offsets.push_back(streams[i]->tellg());
106
0
        }
107
0
    }
108
109
    ~StdIStreamReader()
110
0
    {
111
0
        delete[] locks;
112
0
    }
113
114
    size_t numStreams() const
115
0
    {
116
0
        return streams.size();
117
0
    }
118
119
    bool isOpen() const
120
0
    {
121
0
        return !streams.empty();
122
0
    }
123
124
    bool read(std::size_t iTheadId, Alembic::Util::uint64_t iPos,
125
              Alembic::Util::uint64_t iSize, void* oBuf)
126
0
    {
127
0
        std::size_t streamIndex = 0;
128
0
        if (iTheadId < streams.size())
129
0
        {
130
0
            streamIndex = iTheadId;
131
0
        }
132
133
0
        Alembic::Util::scoped_lock l(locks[streamIndex]);
134
0
        std::istream* stream = streams[streamIndex];
135
136
0
        stream->seekg(iPos + offsets[streamIndex]);
137
0
        if (!stream->good()) return false;
138
139
0
        stream->read(static_cast<char*>(oBuf), iSize);
140
0
        if (!stream->good()) return false;
141
142
0
        return true;
143
0
    }
144
145
private:
146
    std::vector<std::istream*> streams;
147
    std::vector<Alembic::Util::uint64_t> offsets;
148
    Alembic::Util::mutex* locks;
149
};
150
151
152
class FileIStreamReader : public IStreamReader
153
{
154
private:
155
156
// Platform support functions for file access
157
#ifdef _WIN32
158
    typedef int FileDescriptor;
159
160
    static FileDescriptor openFile(const wchar_t * wFileName,
161
                            Alembic::Util::int32_t iFlag)
162
    {
163
        FileDescriptor fid = -1;
164
165
        // One way to prevent writing over a file opened for reading would be to
166
        // pass in _SH_DENYWR instead of _SH_DENYNO.  If we can find a posix
167
        // equivalent we may have an interesting solution for that problem.
168
        _wsopen_s(&fid, wFileName, iFlag | _O_RANDOM, _SH_DENYNO, _S_IREAD);
169
        return fid;
170
    }
171
172
    static void closeFile(FileDescriptor iFid)
173
    {
174
        if (iFid > -1)
175
        {
176
            _close(iFid);
177
        }
178
    }
179
180
    static int getFileLength(FileDescriptor iFile, Alembic::Util::uint64_t & oLength)
181
    {
182
        struct __stat64 buf;
183
184
        int err = _fstat64(iFile, &buf);
185
        if (err < 0) return -1;
186
        if (buf.st_size < 0) return -1;
187
188
        oLength = static_cast<Alembic::Util::uint64_t>(buf.st_size);
189
        return 0;
190
    }
191
192
    static bool readFile(FileDescriptor iFid,
193
                  void * oBuf,
194
                  Alembic::Util::uint64_t iOffset,
195
                  Alembic::Util::uint64_t iSize)
196
  {
197
        void * buf = oBuf;
198
        Alembic::Util::uint64_t offset = iOffset;
199
        Alembic::Util::uint64_t totalRead = 0;
200
201
        HANDLE hFile = reinterpret_cast<HANDLE>(_get_osfhandle(iFid));
202
        DWORD numRead = 0;
203
        do
204
        {
205
            DWORD numToRead = 0;
206
            if ((iSize - totalRead) > MAXDWORD)
207
            {
208
                numToRead = MAXDWORD;
209
            }
210
            else
211
            {
212
                numToRead = static_cast<DWORD>(iSize - totalRead);
213
            }
214
215
            OVERLAPPED overlapped;
216
            memset( &overlapped, 0, sizeof(overlapped));
217
            overlapped.Offset = static_cast<DWORD>(offset);
218
            overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
219
220
            if (!ReadFile(hFile, buf, numToRead, &numRead, &overlapped))
221
            {
222
                return false;
223
            }
224
            totalRead += numRead;
225
            offset += numRead;
226
            buf = static_cast< char * >( buf ) + numRead;
227
        }
228
        while(numRead > 0 && totalRead < iSize);
229
230
        // if we couldn't read what we needed to then something went wrong
231
        if (totalRead < iSize)
232
        {
233
            return false;
234
        }
235
236
        return true;
237
    }
238
239
#else
240
    typedef int FileDescriptor;
241
242
    static FileDescriptor
243
    openFile(const char* iFileName, Alembic::Util::int32_t iFlag)
244
0
    {
245
0
        return open(iFileName, iFlag);
246
0
    }
247
248
    static void closeFile(FileDescriptor iFid)
249
0
    {
250
0
        if (iFid > -1)
251
0
        {
252
0
            close(iFid);
253
0
        }
254
0
    }
255
256
    static int getFileLength(FileDescriptor iFile, Alembic::Util::uint64_t & oLength)
257
0
    {
258
0
        struct stat buf;
259
260
0
        int err = fstat(iFile, &buf);
261
0
        if (err < 0) return -1;
262
0
        if (buf.st_size < 0) return -1;
263
264
0
        oLength = static_cast<size_t>(buf.st_size);
265
0
        return 0;
266
0
    }
267
268
    static bool
269
    readFile(FileDescriptor iFid, void* oBuf, Alembic::Util::uint64_t iOffset,
270
             Alembic::Util::uint64_t iSize)
271
0
    {
272
0
        Alembic::Util::uint64_t totalRead = 0;
273
0
        void* buf = oBuf;
274
0
        off_t offset = iOffset;
275
276
0
        ssize_t numRead = 0;
277
0
        do
278
0
        {
279
0
            Alembic::Util::uint64_t readCount = iSize - totalRead;
280
            // if over 1 GB read it 1 GB chunk at a time to accomodate OSX
281
0
            if (readCount > 1073741824)
282
0
            {
283
0
                readCount = 1073741824;
284
0
            }
285
0
            numRead = pread(iFid, buf, readCount, offset);
286
0
            if (numRead > 0)
287
0
            {
288
0
                totalRead += numRead;
289
0
                offset += numRead;
290
0
                buf = static_cast< char* >( buf ) + numRead;
291
0
            }
292
293
0
            if (numRead < 0 && errno != EINTR)
294
0
            {
295
0
                return false;
296
0
            }
297
0
        } while (numRead > 0 && totalRead < iSize);
298
299
        // if we couldn't read what we needed to then something went wrong
300
0
        if (totalRead < iSize)
301
0
        {
302
0
            return false;
303
0
        }
304
305
0
        return true;
306
0
    }
307
308
#endif
309
310
public:
311
    FileIStreamReader(const std::string& iFileName, std::size_t iNumStreams)
312
0
        : nstreams(iNumStreams)
313
0
    {
314
315
#ifdef _WIN32
316
        // to wchar_t
317
        // get the size of the UTF8 string
318
        int wLength = MultiByteToWideChar(CP_UTF8, 0, iFileName.c_str(), -1, NULL, 0);
319
320
        // allocate buffer
321
        wchar_t* wFileName = (wchar_t*)malloc(wLength * sizeof(wchar_t));
322
        if (!wFileName)
323
          throw std::runtime_error("Unable to allocate buffer  for conversion");
324
325
        // convert to UTF8
326
        if (MultiByteToWideChar(CP_UTF8, 0, iFileName.c_str(), -1, wFileName, wLength) <= 0)
327
          throw std::runtime_error("Unable to convert to wchar_t file name");
328
329
        // open file for read using the UTF8 string
330
        fid = openFile(wFileName, O_RDONLY);
331
    
332
        // free conversion buffer
333
        free(wFileName);
334
#else
335
0
        fid = openFile(iFileName.c_str(), O_RDONLY);
336
0
#endif
337
0
        fileLen = 0;
338
0
        if (getFileLength(fid, fileLen) < 0)
339
0
        {
340
0
            fileLen = 0;
341
0
        }
342
        // don't check the return value here
343
        // IStream::init() will check isOpen
344
0
    }
345
346
    ~FileIStreamReader()
347
0
    {
348
0
        closeFile(fid);
349
0
    }
350
351
    size_t numStreams() const
352
0
    {
353
0
        return nstreams;
354
0
    }
355
356
    bool isOpen() const
357
0
    {
358
0
        return (fid > -1);
359
0
    }
360
361
    Alembic::Util::uint64_t size()
362
0
    {
363
0
        return fileLen;
364
0
    }
365
366
    bool read(std::size_t /*iTheadId*/, Alembic::Util::uint64_t iPos,
367
              Alembic::Util::uint64_t iSize, void* oBuf)
368
0
    {
369
        // Ignore the iThread. There's no need to lock.
370
0
        if (!isOpen()) return false;
371
372
0
        if (fileLen < iSize && fileLen < iSize + iPos)
373
0
        {
374
0
            return false;
375
0
        }
376
377
0
        return readFile(fid, oBuf, iPos, iSize);
378
0
    }
379
380
private:
381
    FileDescriptor fid;
382
    size_t nstreams;
383
    Alembic::Util::uint64_t fileLen;
384
};
385
386
387
388
class MemoryMappedIStreamReader : public IStreamReader
389
{
390
private:
391
392
#ifndef _WIN32
393
    typedef int FileHandle;
394
528
    #define BAD_FILE_HANDLE (-1)
395
396
    static FileHandle openFile(const std::string& iFileName)
397
176
    {
398
176
        int err = open(iFileName.c_str(), O_RDONLY);
399
176
        return err < 0 ? BAD_FILE_HANDLE : err;
400
176
    }
401
402
    static void closeFile(FileHandle iFile)
403
176
    {
404
176
        if (iFile != BAD_FILE_HANDLE)
405
176
        {
406
176
            close(iFile);
407
176
        }
408
176
    }
409
410
    static int getFileLength(FileHandle iFile, size_t& oLength)
411
176
    {
412
176
        struct stat buf;
413
414
176
        int err = fstat(iFile, &buf);
415
176
        if (err < 0) return -1;
416
176
        if (buf.st_size < 0) return -1;
417
418
176
        oLength = static_cast<size_t>(buf.st_size);
419
176
        return 0;
420
176
    }
421
422
    struct MappedRegion
423
    {
424
        size_t len;
425
        void* p;
426
427
176
        MappedRegion() : len(0), p(NULL)
428
176
        {
429
176
        }
430
431
        ~MappedRegion()
432
176
        {
433
176
            close();
434
176
        }
435
436
        bool isMapped() const
437
176
        {
438
176
            return p != NULL;
439
176
        }
440
441
        void map(FileHandle iFile, size_t iLength)
442
176
        {
443
176
            close();
444
445
176
            void* m = mmap(NULL, iLength, PROT_READ, MAP_PRIVATE, iFile, 0);
446
176
            if (m == MAP_FAILED) return;
447
448
176
            p = m;
449
176
            len = iLength;
450
176
        }
451
452
        void close()
453
528
        {
454
528
            if (p)
455
176
            {
456
176
                munmap(p, len);
457
176
                p = NULL;
458
176
            }
459
528
        }
460
461
    };
462
463
#else // _WIN32 defined
464
    typedef HANDLE FileHandle;
465
    #define BAD_FILE_HANDLE (INVALID_HANDLE_VALUE)
466
467
    static FileHandle openFile(const std::string& iFileName)
468
    {
469
        // to wchar_t
470
        // get the size of the UTF8 string
471
        int wLength = MultiByteToWideChar(CP_UTF8, 0, iFileName.c_str(), -1, NULL, 0);
472
473
        // allocate buffer
474
        wchar_t* wFileName = (wchar_t*)malloc(wLength * sizeof(wchar_t));
475
        if (!wFileName)
476
          throw std::runtime_error("Unable to allocate buffer  for conversion");
477
478
        // convert to UTF8
479
        if (MultiByteToWideChar(CP_UTF8, 0, iFileName.c_str(), -1, wFileName, wLength) <= 0)
480
          throw std::runtime_error("Unable to convert to wchar_t file name");
481
482
        // open file for read using the UTF8 string
483
        // Use both FILE_SHARE_READ and FILE_SHARE_WRITE as the share mode.
484
        // Without FILE_SHARE_WRITE, this will fail when trying to open a file that is already open for writing.
485
        FileHandle fh = CreateFileW(wFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
486
487
        // free conversion buffer
488
        free(wFileName);
489
490
        return fh;
491
    }
492
493
    static void closeFile(FileHandle iFile)
494
    {
495
        if (iFile != INVALID_HANDLE_VALUE)
496
        {
497
            CloseHandle(iFile);
498
        }
499
    }
500
501
    static int getFileLength(FileHandle iFile, size_t& oLength)
502
    {
503
        LARGE_INTEGER length;
504
        length.QuadPart = 0;
505
506
        BOOL success = GetFileSizeEx(iFile, &length);
507
        if (!success) return -1;
508
        if (length.QuadPart < 0) return -1;
509
510
        oLength = static_cast<size_t>(length.QuadPart);
511
        return 0;
512
    }
513
514
    struct MappedRegion
515
    {
516
        Alembic::Util::uint64_t len;
517
        void* p;
518
519
        MappedRegion() : len(0), p(NULL)
520
        {
521
        }
522
523
        ~MappedRegion()
524
        {
525
            close();
526
        }
527
528
        bool isMapped() const
529
        {
530
            return p != NULL;
531
        }
532
533
        void map(FileHandle iFile, Alembic::Util::uint64_t iLength)
534
        {
535
            close();
536
537
            DWORD sizeHigh = static_cast<DWORD>(iLength >> 32);
538
            DWORD sizeLow = static_cast<DWORD>(iLength);
539
            HANDLE mapping = CreateFileMappingA(iFile, NULL, PAGE_READONLY, sizeHigh, sizeLow, NULL);
540
            if (mapping == NULL) return;
541
542
            LPVOID view = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, iLength);
543
544
            // regardless of whether we have a successful view, close the mapping
545
            // the underlying file mapping will remain open as long as the view is open
546
            CloseHandle(mapping);
547
548
            if (view != NULL)
549
            {
550
                p = view;
551
                len = iLength;
552
            }
553
        }
554
555
        void close()
556
        {
557
            if (p)
558
            {
559
                UnmapViewOfFile(p);
560
                p = NULL;
561
            }
562
        }
563
564
    };
565
#endif
566
567
568
public:
569
    MemoryMappedIStreamReader(const std::string& iFileName,
570
                              std::size_t iNumStreams)
571
176
        : nstreams(iNumStreams), fileName(iFileName),
572
176
          fileHandle(BAD_FILE_HANDLE)
573
176
    {
574
176
        fileHandle = openFile(iFileName);
575
176
        if (fileHandle == BAD_FILE_HANDLE) return;
576
577
176
        size_t len = 0;
578
176
        int err = getFileLength(fileHandle, len);
579
176
        if (err < 0) return;
580
581
176
        mappedRegion.map(fileHandle, len);
582
176
    }
583
584
    ~MemoryMappedIStreamReader()
585
176
    {
586
176
        mappedRegion.close();
587
176
        closeFile(fileHandle);
588
176
    }
589
590
    bool isOpen() const
591
176
    {
592
176
        return mappedRegion.isMapped();
593
176
    }
594
595
    size_t numStreams() const
596
0
    {
597
        // memory mapped files support 'unlimited' streams, but just report
598
        // the number of streams we were opened with
599
0
        return nstreams;
600
0
    }
601
602
    Alembic::Util::uint64_t size()
603
170
    {
604
170
        return static_cast<Alembic::Util::uint64_t>(mappedRegion.len);
605
170
    }
606
607
    bool read(std::size_t iStream, Alembic::Util::uint64_t iPos,
608
              Alembic::Util::uint64_t iSize, void* oBuf)
609
2.60k
    {
610
2.60k
        if (iSize > mappedRegion.len || iPos > mappedRegion.len || iPos + iSize > mappedRegion.len) return false;
611
612
2.55k
        const char* p = static_cast<const char*>(mappedRegion.p) + iPos;
613
2.55k
        std::memcpy(oBuf, p, iSize);
614
615
2.55k
        return true;
616
2.60k
    }
617
618
private:
619
    std::size_t nstreams;
620
    std::string fileName;
621
    FileHandle fileHandle;
622
    MappedRegion mappedRegion;
623
};
624
625
626
IStreamReaderPtr constructStreamReader(
627
    const std::string & iFileName,
628
    std::size_t iNumStreams,
629
    bool iUseMMap)
630
176
{
631
    // if allowed by the options, use memory mapped file access
632
176
    if (iUseMMap)
633
176
    {
634
176
        return IStreamReaderPtr(
635
176
            new MemoryMappedIStreamReader(iFileName, iNumStreams));
636
176
    }
637
638
    // otherwise, use file streams
639
0
    return IStreamReaderPtr(new FileIStreamReader(iFileName, iNumStreams));
640
176
}
641
642
IStreamReaderPtr constructStreamReader(
643
    const std::vector< std::istream * > & iStreams)
644
0
{
645
    // This construction method only supports the std::istream reader
646
0
    return IStreamReaderPtr(new StdIStreamReader(iStreams));
647
0
}
648
649
650
}  // anonymous namespace
651
652
653
654
class IStreams::PrivateData
655
{
656
public:
657
    PrivateData()
658
176
    {
659
176
        valid = false;
660
176
        frozen = false;
661
176
        version = 0;
662
176
        size = 0;
663
176
    }
664
665
    void init(IStreamReaderPtr iReader, size_t iNumStreams)
666
176
    {
667
        // simple temporary endian check
668
176
        union
669
176
        {
670
176
            Util::uint32_t l;
671
176
            char c[4];
672
176
        } u;
673
674
176
        u.l = 0x01234567;
675
676
176
        if (u.c[0] != 0x67)
677
0
        {
678
0
            throw std::runtime_error(
679
0
                "Ogawa currently only supports little-endian reading.");
680
0
        }
681
682
176
        if (iNumStreams == 0 || iReader == NULL || !iReader->isOpen()) return;
683
684
176
        Alembic::Util::uint64_t firstGroupPos = 0;
685
686
346
        for (std::size_t i = 0; i < iNumStreams; ++i)
687
176
        {
688
176
            char header[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
689
690
176
            iReader->read(i, 0, 16, static_cast<void*>(header));
691
176
            std::string magicStr(header, 5);
692
176
            if (magicStr != "Ogawa")
693
6
            {
694
6
                frozen = false;
695
6
                valid = false;
696
6
                version = 0;
697
6
                return;
698
6
            }
699
170
            bool filefrozen = (header[5] == char(0xff));
700
170
            Alembic::Util::uint16_t topvers = header[6];
701
170
            Alembic::Util::uint16_t fileversion = (topvers << 8) | header[7];
702
170
            Alembic::Util::uint64_t groupPos = *((Alembic::Util::uint64_t*) (&(header[8])));
703
170
            Alembic::Util::uint64_t filesize = iReader->size();
704
705
170
            if (i == 0)
706
170
            {
707
170
                firstGroupPos = groupPos;
708
170
                frozen = filefrozen;
709
170
                version = fileversion;
710
170
                size = filesize;
711
170
            }
712
                // all the streams have to agree, or we are invalid
713
0
            else if (firstGroupPos != groupPos || frozen != filefrozen ||
714
0
                     version != fileversion || size != filesize)
715
0
            {
716
0
                frozen = false;
717
0
                valid = false;
718
0
                version = 0;
719
0
                return;
720
0
            }
721
170
        }
722
723
        // if we reach here, and we're a known version, then we're valid
724
170
        if (version == 1)
725
170
        {
726
170
            reader = iReader;        // preserve the reader
727
170
            valid = true;
728
170
        }
729
170
    }
730
731
732
    bool valid;
733
    bool frozen;
734
    Alembic::Util::uint16_t version;
735
    Alembic::Util::uint64_t size;
736
737
    IStreamReaderPtr reader;
738
};
739
740
IStreams::IStreams(const std::string & iFileName, std::size_t iNumStreams,
741
                   bool iUseMMap) :
742
176
    mData(new IStreams::PrivateData())
743
176
{
744
176
    IStreamReaderPtr reader = constructStreamReader(iFileName, iNumStreams,
745
176
                                                    iUseMMap);
746
176
    mData->init(reader, 1);
747
176
}
748
749
IStreams::IStreams(const std::vector< std::istream * > & iStreams) :
750
0
    mData(new IStreams::PrivateData())
751
0
{
752
0
    IStreamReaderPtr reader = constructStreamReader(iStreams);
753
0
    mData->init(reader, reader->numStreams());
754
0
}
755
756
IStreams::~IStreams()
757
176
{
758
176
}
759
760
bool IStreams::isValid()
761
3.17k
{
762
3.17k
    return mData->valid;
763
3.17k
}
764
765
bool IStreams::isFrozen()
766
170
{
767
170
    return mData->frozen;
768
170
}
769
770
Alembic::Util::uint16_t IStreams::getVersion()
771
0
{
772
0
    return mData->version;
773
0
}
774
775
Alembic::Util::uint64_t IStreams::getSize()
776
1.18k
{
777
1.18k
    return mData->size;
778
1.18k
}
779
780
void IStreams::read(std::size_t iThreadId, Alembic::Util::uint64_t iPos,
781
                    Alembic::Util::uint64_t iSize, void * oBuf)
782
2.42k
{
783
2.42k
    if (!isValid())
784
0
    {
785
0
        return;
786
0
    }
787
788
2.42k
    bool success = mData->reader->read(iThreadId, iPos, iSize, oBuf);
789
2.42k
    if (!success)
790
41
    {
791
41
        throw std::runtime_error(
792
41
            "Ogawa IStreams::read failed.");
793
41
    }
794
2.42k
}
795
796
} // End namespace ALEMBIC_VERSION_NS
797
} // End namespace Ogawa
798
} // End namespace Alembic