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