Field3D
IStreams.cpp
Go to the documentation of this file.
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 "IStreams.h"
37#include <fstream>
38#include <stdexcept>
39
40namespace Alembic {
41namespace Ogawa {
42namespace ALEMBIC_VERSION_NS {
43
44class IStreams::PrivateData
45{
46public:
47 PrivateData()
48 {
49 locks = NULL;
50 valid = false;
51 frozen = false;
52 version = 0;
53 }
54
55 ~PrivateData()
56 {
57 if (locks)
58 {
59 delete [] locks;
60 }
61
62 // only cleanup if we were the ones who opened it
63 if (!fileName.empty())
64 {
65 std::vector<std::istream *>::iterator it;
66 for (it = streams.begin(); it != streams.end(); ++it)
67 {
68 std::ifstream * filestream = dynamic_cast<std::ifstream *>(*it);
69 if (filestream)
70 {
71 filestream->close();
72 delete filestream;
73 }
74 }
75 }
76 }
77
78 std::vector<std::istream *> streams;
79 std::vector<Alembic::Util::uint64_t> offsets;
80 Alembic::Util::mutex * locks;
81 std::string fileName;
82 bool valid;
83 bool frozen;
84 Alembic::Util::uint16_t version;
85};
86
87IStreams::IStreams(const std::string & iFileName, std::size_t iNumStreams) :
88 mData(new IStreams::PrivateData())
89{
90
91 std::ifstream * filestream = new std::ifstream;
92 filestream->open(iFileName.c_str(), std::ios::binary);
93
94 if (filestream->is_open())
95 {
96 mData->fileName = iFileName;
97 }
98 else
99 {
100 delete filestream;
101 return;
102 }
103
104 mData->streams.push_back(filestream);
105 init();
106 if (!mData->valid || mData->version != 1)
107 {
108 mData->streams.clear();
109 filestream->close();
110 delete filestream;
111 }
112 else
113 {
114 // we are valid, so we'll allocate (but not open) the others
115 mData->streams.resize(iNumStreams, NULL);
116 mData->offsets.resize(iNumStreams, 0);
117 }
118 mData->locks = new Alembic::Util::mutex[mData->streams.size()];
119}
120
121IStreams::IStreams(const std::vector< std::istream * > & iStreams) :
122 mData(new IStreams::PrivateData())
123{
124 mData->streams = iStreams;
125 init();
126 if (!mData->valid || mData->version != 1)
127 {
128 mData->streams.clear();
129 return;
130 }
131
132 mData->locks = new Alembic::Util::mutex[mData->streams.size()];
133}
134
135void IStreams::init()
136{
137 // simple temporary endian check
138 union {
139 Util::uint32_t l;
140 char c[4];
141 } u;
142
143 u.l = 0x01234567;
144
145 if (u.c[0] != 0x67)
146 {
147 throw std::runtime_error(
148 "Ogawa currently only supports little-endian reading.");
149 }
150
151 if (mData->streams.empty())
152 {
153 return;
154 }
155
156 Alembic::Util::uint64_t firstGroupPos = 0;
157
158 for (std::size_t i = 0; i < mData->streams.size(); ++i)
159 {
160 char header[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
161 mData->offsets.push_back(mData->streams[i]->tellg());
162 mData->streams[i]->read(header, 16);
163 std::string magicStr(header, 5);
164 if (magicStr != "Ogawa")
165 {
166 mData->frozen = false;
167 mData->valid = false;
168 mData->version = 0;
169 return;
170 }
171 bool frozen = (header[5] == char(0xff));
172 Alembic::Util::uint16_t version = (header[6] << 8) | header[7];
173 Alembic::Util::uint64_t groupPos =
174 *((Alembic::Util::uint64_t *)(&(header[8])));
175
176 if (i == 0)
177 {
179 mData->frozen = frozen;
180 mData->version = version;
181 }
182 // all the streams have to agree, or we are invalid
183 else if (firstGroupPos != groupPos || mData->frozen != frozen ||
184 mData->version != version)
185 {
186 mData->frozen = false;
187 mData->valid = false;
188 mData->version = 0;
189 return;
190 }
191 }
192 mData->valid = true;
193}
194
195IStreams::~IStreams()
196{
197}
198
199bool IStreams::isValid()
200{
201 return mData->valid;
202}
203
204bool IStreams::isFrozen()
205{
206 return mData->frozen;
207}
208
209Alembic::Util::uint16_t IStreams::getVersion()
210{
211 return mData->version;
212}
213
214void IStreams::read(std::size_t iThreadId, Alembic::Util::uint64_t iPos,
215 Alembic::Util::uint64_t iSize, void * oBuf)
216{
217 if (!isValid())
218 {
219 return;
220 }
221
222 std::size_t threadId = 0;
223 if (iThreadId < mData->streams.size())
224 {
226 }
227
228 {
229 Alembic::Util::scoped_lock l(mData->locks[threadId]);
230 std::istream * stream = mData->streams[threadId];
231
232 // the file hasn't been opened for this id yet
233 if (stream == NULL && !mData->fileName.empty())
234 {
235 std::ifstream * filestream = new std::ifstream;
236 filestream->open(mData->fileName.c_str(), std::ios::binary);
237
238 if (filestream->is_open())
239 {
240 stream = filestream;
241 mData->streams[threadId] = filestream;
242 mData->offsets[threadId] = filestream->tellg();
243 }
244 // couldnt open the file, do cleanup
245 else
246 {
247 delete filestream;
248
249 // read from thread 0 instead until it can be opened
250 if (threadId != 0)
251 {
252 read(0, iPos, iSize, oBuf);
253 }
254 return;
255 }
256 }
257 stream->seekg(iPos + mData->offsets[threadId]);
258 stream->read((char *)oBuf, iSize);
259 }
260}
261
262} // End namespace ALEMBIC_VERSION_NS
263} // End namespace Ogawa
264} // End namespace Alembic
#define FIELD3D_MTX_T
Definition StdMathLib.h:99