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/OGroup.h>
37 #include <Alembic/Ogawa/OArchive.h>
38 #include <Alembic/Ogawa/OData.h>
39 #include <Alembic/Ogawa/OStream.h>
40
41 namespace Alembic {
42 namespace Ogawa {
43 namespace ALEMBIC_VERSION_NS {
44
45 typedef std::pair< OGroupPtr, Alembic::Util::uint64_t > ParentPair;
46 typedef std::vector< ParentPair > ParentPairVec;
47
48 class OGroup::PrivateData
49 {
50 public:
PrivateData()51 PrivateData() {};
~PrivateData()52 ~PrivateData() {};
53
54 OStreamPtr stream;
55
56 // used before freeze
57 ParentPairVec parents;
58
59 // used before and after freeze
60 std::vector<Alembic::Util::uint64_t> childVec;
61
62 // set after freeze
63 Alembic::Util::uint64_t pos;
64 };
65
OGroup(OGroupPtr iParent,Alembic::Util::uint64_t iIndex)66 OGroup::OGroup(OGroupPtr iParent, Alembic::Util::uint64_t iIndex)
67 : mData(new OGroup::PrivateData())
68 {
69 mData->stream = iParent->mData->stream;
70 mData->parents.push_back( ParentPair(iParent, iIndex) );
71 mData->pos = INVALID_GROUP;
72 }
73
OGroup(OStreamPtr iStream)74 OGroup::OGroup(OStreamPtr iStream)
75 : mData(new OGroup::PrivateData())
76 {
77 mData->stream = iStream;
78 mData->parents.push_back(ParentPair(OGroupPtr(), 0));
79 mData->pos = INVALID_GROUP;
80 }
81
~OGroup()82 OGroup::~OGroup()
83 {
84 freeze();
85 }
86
addGroup()87 OGroupPtr OGroup::addGroup()
88 {
89 OGroupPtr child;
90 if (!isFrozen())
91 {
92 mData->childVec.push_back(0);
93 child.reset(new OGroup(shared_from_this(), mData->childVec.size() - 1));
94 }
95 return child;
96 }
97
createData(Alembic::Util::uint64_t iSize,const void * iData)98 ODataPtr OGroup::createData(Alembic::Util::uint64_t iSize, const void * iData)
99 {
100 ODataPtr child;
101 if (isFrozen())
102 {
103 return child;
104 }
105
106 if (iSize == 0)
107 {
108 mData->childVec.push_back(EMPTY_DATA);
109 child.reset(new OData());
110 return child;
111 }
112
113 Alembic::Util::uint64_t pos = mData->stream->getAndSeekEndPos();
114
115 Alembic::Util::uint64_t size = iSize;
116 mData->stream->write(&size, 8);
117 mData->stream->write(iData, iSize);
118
119 child.reset(new OData(mData->stream, pos, iSize));
120
121 return child;
122 }
123
addData(Alembic::Util::uint64_t iSize,const void * iData)124 ODataPtr OGroup::addData(Alembic::Util::uint64_t iSize, const void * iData)
125 {
126 ODataPtr child = OGroup::createData(iSize, iData);
127 if (child)
128 {
129 // flip top bit for data so we can easily distinguish between it and
130 // a group
131 mData->childVec.push_back(child->getPos() | 0x8000000000000000ULL);
132 }
133 return child;
134 }
135
createData(Alembic::Util::uint64_t iNumData,const Alembic::Util::uint64_t * iSizes,const void ** iDatas)136 ODataPtr OGroup::createData(Alembic::Util::uint64_t iNumData,
137 const Alembic::Util::uint64_t * iSizes,
138 const void ** iDatas)
139 {
140 ODataPtr child;
141 if (isFrozen())
142 {
143 return child;
144 }
145
146 Alembic::Util::uint64_t totalSize = 0;
147 for (Alembic::Util::uint64_t i = 0; i < iNumData; ++i)
148 {
149 totalSize += iSizes[i];
150 }
151
152 if (totalSize == 0)
153 {
154 mData->childVec.push_back(EMPTY_DATA);
155 child.reset(new OData());
156 return child;
157 }
158
159 Alembic::Util::uint64_t pos = mData->stream->getAndSeekEndPos();
160
161 mData->stream->write(&totalSize, 8);
162 for (Alembic::Util::uint64_t i = 0; i < iNumData; ++i)
163 {
164 Alembic::Util::uint64_t size = iSizes[i];
165 if (size != 0)
166 {
167 mData->stream->write(iDatas[i], size);
168 }
169 }
170
171 child.reset(new OData(mData->stream, pos, totalSize));
172
173 return child;
174 }
175
addData(Alembic::Util::uint64_t iNumData,const Alembic::Util::uint64_t * iSizes,const void ** iDatas)176 ODataPtr OGroup::addData(Alembic::Util::uint64_t iNumData,
177 const Alembic::Util::uint64_t * iSizes,
178 const void ** iDatas)
179 {
180 ODataPtr child = createData(iNumData, iSizes, iDatas);
181 if (child)
182 {
183 // flip top bit for data so we can easily distinguish between it and
184 // a group
185 mData->childVec.push_back(child->getPos() | 0x8000000000000000ULL);
186 }
187 return child;
188 }
189
addData(ODataPtr iData)190 void OGroup::addData(ODataPtr iData)
191 {
192 if (!isFrozen())
193 {
194 mData->childVec.push_back(iData->getPos() | 0x8000000000000000ULL);
195 }
196 }
197
addGroup(OGroupPtr iGroup)198 void OGroup::addGroup(OGroupPtr iGroup)
199 {
200 if (!isFrozen())
201 {
202 if (iGroup->isFrozen())
203 {
204 mData->childVec.push_back(iGroup->mData->pos);
205 }
206 else
207 {
208 mData->childVec.push_back(EMPTY_GROUP);
209 iGroup->mData->parents.push_back(
210 ParentPair(shared_from_this(), mData->childVec.size() - 1));
211 }
212 }
213 }
214
addEmptyGroup()215 void OGroup::addEmptyGroup()
216 {
217 if (!isFrozen())
218 {
219 mData->childVec.push_back(EMPTY_GROUP);
220 }
221 }
222
addEmptyData()223 void OGroup::addEmptyData()
224 {
225 if (!isFrozen())
226 {
227 mData->childVec.push_back(EMPTY_DATA);
228 }
229 }
230
231 // no more children can be added, commit to the stream
freeze()232 void OGroup::freeze()
233 {
234 // bail if we've already done this work
235 if (isFrozen())
236 {
237 return;
238 }
239
240 // we ended up not adding any children, so no need to commit this group
241 // to disk, use empty group instead
242 if (mData->childVec.empty())
243 {
244 mData->pos = 0;
245 }
246 else
247 {
248 mData->pos = mData->stream->getAndSeekEndPos();
249 Alembic::Util::uint64_t size = mData->childVec.size();
250 mData->stream->write(&size, 8);
251 mData->stream->write(&mData->childVec.front(), size*8);
252 }
253
254 // go through and update each of the parents
255 ParentPairVec::iterator it;
256 for(it = mData->parents.begin(); it != mData->parents.end(); ++it)
257 {
258 // special group owned by the archive
259 if (!it->first && it->second == 0)
260 {
261 mData->stream->seek(8);
262 mData->stream->write(&mData->pos, 8);
263 continue;
264 }
265 else if (it->first->isFrozen())
266 {
267 mData->stream->seek(it->first->mData->pos + (it->second + 1) * 8);
268 mData->stream->write(&mData->pos, 8);
269 }
270 it->first->mData->childVec[it->second] = mData->pos;
271 }
272
273 mData->parents.clear();
274
275 }
276
isFrozen()277 bool OGroup::isFrozen()
278 {
279 return mData->pos != INVALID_GROUP;
280 }
281
getNumChildren() const282 Alembic::Util::uint64_t OGroup::getNumChildren() const
283 {
284 return mData->childVec.size();
285 }
286
isChildGroup(Alembic::Util::uint64_t iIndex) const287 bool OGroup::isChildGroup(Alembic::Util::uint64_t iIndex) const
288 {
289 return (iIndex < mData->childVec.size() &&
290 (mData->childVec[iIndex] & EMPTY_DATA) == 0);
291 }
292
isChildData(Alembic::Util::uint64_t iIndex) const293 bool OGroup::isChildData(Alembic::Util::uint64_t iIndex) const
294 {
295 return (iIndex < mData->childVec.size() &&
296 (mData->childVec[iIndex] & EMPTY_DATA) != 0);
297 }
298
isChildEmptyGroup(Alembic::Util::uint64_t iIndex) const299 bool OGroup::isChildEmptyGroup(Alembic::Util::uint64_t iIndex) const
300 {
301 return (iIndex < mData->childVec.size() &&
302 mData->childVec[iIndex] == EMPTY_GROUP);
303 }
304
isChildEmptyData(Alembic::Util::uint64_t iIndex) const305 bool OGroup::isChildEmptyData(Alembic::Util::uint64_t iIndex) const
306 {
307 return (iIndex < mData->childVec.size() &&
308 mData->childVec[iIndex] == EMPTY_DATA);
309 }
310
replaceData(Alembic::Util::uint64_t iIndex,ODataPtr iData)311 void OGroup::replaceData(Alembic::Util::uint64_t iIndex, ODataPtr iData)
312 {
313 if (!isChildData(iIndex))
314 {
315 return;
316 }
317
318 Alembic::Util::uint64_t pos = iData->getPos() | 0x8000000000000000ULL;
319 if (isFrozen())
320 {
321 mData->stream->seek(mData->pos + (iIndex + 1) * 8);
322 mData->stream->write(&pos, 8);
323 }
324 mData->childVec[iIndex] = pos;
325 }
326
327 } // End namespace ALEMBIC_VERSION_NS
328 } // End namespace Ogawa
329 } // End namespace Alembic
330