Field3D
OGroup.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 "OGroup.h"
37 #include "OArchive.h"
38 #include "OData.h"
39 #include "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:
51  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 
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 
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 
82 OGroup::~OGroup()
83 {
84  freeze();
85 }
86 
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 
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 
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 
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 
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 
190 void OGroup::addData(ODataPtr iData)
191 {
192  if (!isFrozen())
193  {
194  mData->childVec.push_back(iData->getPos() | 0x8000000000000000ULL);
195  }
196 }
197 
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 
215 void OGroup::addEmptyGroup()
216 {
217  if (!isFrozen())
218  {
219  mData->childVec.push_back(EMPTY_GROUP);
220  }
221 }
222 
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
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 
277 bool OGroup::isFrozen()
278 {
279  return mData->pos != INVALID_GROUP;
280 }
281 
282 Alembic::Util::uint64_t OGroup::getNumChildren() const
283 {
284  return mData->childVec.size();
285 }
286 
287 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 
293 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 
299 bool OGroup::isChildEmptyGroup(Alembic::Util::uint64_t iIndex) const
300 {
301  return (iIndex < mData->childVec.size() &&
302  mData->childVec[iIndex] == EMPTY_GROUP);
303 }
304 
305 bool OGroup::isChildEmptyData(Alembic::Util::uint64_t iIndex) const
306 {
307  return (iIndex < mData->childVec.size() &&
308  mData->childVec[iIndex] == EMPTY_DATA);
309 }
310 
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
Alembic::Ogawa::ALEMBIC_VERSION_NS::ParentPair
std::pair< OGroupPtr, Alembic::Util::uint64_t > ParentPair
Definition: OGroup.cpp:45
Alembic
Definition: OgawaFwd.h:77
Alembic::Ogawa::ALEMBIC_VERSION_NS::ParentPairVec
std::vector< ParentPair > ParentPairVec
Definition: OGroup.cpp:46