Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright Contributors to the OpenVDB Project | ||
2 | // SPDX-License-Identifier: MPL-2.0 | ||
3 | |||
4 | #include "Stream.h" | ||
5 | |||
6 | #include "File.h" ///< @todo refactor | ||
7 | #include "GridDescriptor.h" | ||
8 | #include "TempFile.h" | ||
9 | #include <openvdb/Exceptions.h> | ||
10 | #include <cstdint> | ||
11 | #include <boost/iostreams/copy.hpp> | ||
12 | #include <cstdio> // for remove() | ||
13 | #include <functional> // for std::bind() | ||
14 | #include <iostream> | ||
15 | #include <vector> | ||
16 | |||
17 | |||
18 | namespace openvdb { | ||
19 | OPENVDB_USE_VERSION_NAMESPACE | ||
20 | namespace OPENVDB_VERSION_NAME { | ||
21 | namespace io { | ||
22 | |||
23 | struct Stream::Impl | ||
24 | { | ||
25 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
10 | Impl(): mOutputStream{nullptr} {} |
26 | 2 | Impl(const Impl& other) { *this = other; } | |
27 | 2 | Impl& operator=(const Impl& other) | |
28 | { | ||
29 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (&other != this) { |
30 | mMeta = other.mMeta; ///< @todo deep copy? | ||
31 | mGrids = other.mGrids; ///< @todo deep copy? | ||
32 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | mOutputStream = other.mOutputStream; |
33 | mFile.reset(); | ||
34 | } | ||
35 | 2 | return *this; | |
36 | } | ||
37 | |||
38 | MetaMap::Ptr mMeta; | ||
39 | GridPtrVecPtr mGrids; | ||
40 | std::ostream* mOutputStream; | ||
41 | std::unique_ptr<File> mFile; | ||
42 | }; | ||
43 | |||
44 | |||
45 | //////////////////////////////////////// | ||
46 | |||
47 | |||
48 | namespace { | ||
49 | |||
50 | /// @todo Use MappedFile auto-deletion instead. | ||
51 | void | ||
52 | 3 | removeTempFile(const std::string expectedFilename, const std::string& filename) | |
53 | { | ||
54 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (filename == expectedFilename) { |
55 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | if (0 != std::remove(filename.c_str())) { |
56 | ✗ | std::string mesg = getErrorString(); | |
57 | ✗ | if (!mesg.empty()) mesg = " (" + mesg + ")"; | |
58 | OPENVDB_LOG_WARN("failed to remove temporary file " << filename << mesg); | ||
59 | } | ||
60 | } | ||
61 | 3 | } | |
62 | |||
63 | } | ||
64 | |||
65 | |||
66 |
1/2✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | Stream::Stream(std::istream& is, bool delayLoad): mImpl(new Impl) |
67 | { | ||
68 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (!is) return; |
69 | |||
70 |
3/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
|
3 | if (delayLoad && Archive::isDelayedLoadingEnabled()) { |
71 | // Copy the contents of the stream to a temporary private file | ||
72 | // and open the file instead. | ||
73 | 3 | std::unique_ptr<TempFile> tempFile; | |
74 | try { | ||
75 |
2/4✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
3 | tempFile.reset(new TempFile); |
76 | ✗ | } catch (std::exception& e) { | |
77 | std::string mesg; | ||
78 | ✗ | if (e.what()) mesg = std::string(" (") + e.what() + ")"; | |
79 | OPENVDB_LOG_WARN("failed to create a temporary file for delayed loading" << mesg | ||
80 | << "; will read directly from the input stream instead"); | ||
81 | } | ||
82 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (tempFile) { |
83 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | boost::iostreams::copy(is, *tempFile); |
84 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | const std::string& filename = tempFile->filename(); |
85 |
2/4✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
3 | mImpl->mFile.reset(new File(filename)); |
86 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | mImpl->mFile->setCopyMaxBytes(0); // don't make a copy of the temporary file |
87 | /// @todo Need to pass auto-deletion flag to MappedFile. | ||
88 |
2/4✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
6 | mImpl->mFile->open(delayLoad, |
89 |
0/2✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
3 | std::bind(&removeTempFile, filename, std::placeholders::_1)); |
90 | } | ||
91 | } | ||
92 | |||
93 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (!mImpl->mFile) { |
94 | ✗ | readHeader(is); | |
95 | |||
96 | // Tag the input stream with the library and file format version numbers | ||
97 | // and the compression options specified in the header. | ||
98 | ✗ | StreamMetadata::Ptr streamMetadata(new StreamMetadata); | |
99 | ✗ | io::setStreamMetadataPtr(is, streamMetadata, /*transfer=*/false); | |
100 | ✗ | io::setVersion(is, libraryVersion(), fileVersion()); | |
101 | ✗ | io::setDataCompression(is, compression()); | |
102 | |||
103 | // Read in the VDB metadata. | ||
104 | ✗ | mImpl->mMeta.reset(new MetaMap); | |
105 | ✗ | mImpl->mMeta->readMeta(is); | |
106 | |||
107 | // Read in the number of grids. | ||
108 | ✗ | const int32_t gridCount = readGridCount(is); | |
109 | |||
110 | // Read in all grids and insert them into mGrids. | ||
111 | ✗ | mImpl->mGrids.reset(new GridPtrVec); | |
112 | ✗ | std::vector<GridDescriptor> descriptors; | |
113 | ✗ | descriptors.reserve(gridCount); | |
114 | Archive::NamedGridMap namedGrids; | ||
115 | ✗ | for (int32_t i = 0; i < gridCount; ++i) { | |
116 | ✗ | GridDescriptor gd; | |
117 | ✗ | gd.read(is); | |
118 | ✗ | descriptors.push_back(gd); | |
119 | ✗ | GridBase::Ptr grid = readGrid(gd, is); | |
120 | ✗ | mImpl->mGrids->push_back(grid); | |
121 | ✗ | namedGrids[gd.uniqueName()] = grid; | |
122 | } | ||
123 | |||
124 | // Connect instances (grids that share trees with other grids). | ||
125 | ✗ | for (size_t i = 0, N = descriptors.size(); i < N; ++i) { | |
126 | ✗ | Archive::connectInstance(descriptors[i], namedGrids); | |
127 | } | ||
128 | } | ||
129 | } | ||
130 | |||
131 | |||
132 | ✗ | Stream::Stream(): mImpl(new Impl) | |
133 | { | ||
134 | } | ||
135 | |||
136 | |||
137 |
1/2✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
|
7 | Stream::Stream(std::ostream& os): mImpl(new Impl) |
138 | { | ||
139 | 7 | mImpl->mOutputStream = &os; | |
140 | 7 | } | |
141 | |||
142 | |||
143 | 28 | Stream::~Stream() | |
144 | { | ||
145 | 28 | } | |
146 | |||
147 | |||
148 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | Stream::Stream(const Stream& other): Archive(other), mImpl(new Impl(*other.mImpl)) |
149 | { | ||
150 | 2 | } | |
151 | |||
152 | |||
153 | Stream& | ||
154 | ✗ | Stream::operator=(const Stream& other) | |
155 | { | ||
156 | ✗ | if (&other != this) { | |
157 | ✗ | mImpl.reset(new Impl(*other.mImpl)); | |
158 | } | ||
159 | ✗ | return *this; | |
160 | } | ||
161 | |||
162 | |||
163 | SharedPtr<Archive> | ||
164 | 2 | Stream::copy() const | |
165 | { | ||
166 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
4 | return SharedPtr<Archive>(new Stream(*this)); |
167 | } | ||
168 | |||
169 | |||
170 | //////////////////////////////////////// | ||
171 | |||
172 | |||
173 | GridBase::Ptr | ||
174 | ✗ | Stream::readGrid(const GridDescriptor& gd, std::istream& is) const | |
175 | { | ||
176 | ✗ | GridBase::Ptr grid; | |
177 | |||
178 | ✗ | if (!GridBase::isRegistered(gd.gridType())) { | |
179 | ✗ | OPENVDB_THROW(TypeError, "can't read grid \"" | |
180 | << GridDescriptor::nameAsString(gd.uniqueName()) << | ||
181 | "\" from input stream because grid type " << gd.gridType() << " is unknown"); | ||
182 | } else { | ||
183 | ✗ | grid = GridBase::createGrid(gd.gridType()); | |
184 | ✗ | if (grid) grid->setSaveFloatAsHalf(gd.saveFloatAsHalf()); | |
185 | |||
186 | ✗ | Archive::readGrid(grid, gd, is); | |
187 | } | ||
188 | ✗ | return grid; | |
189 | } | ||
190 | |||
191 | |||
192 | void | ||
193 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | Stream::write(const GridCPtrVec& grids, const MetaMap& metadata) const |
194 | { | ||
195 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (mImpl->mOutputStream == nullptr) { |
196 | ✗ | OPENVDB_THROW(ValueError, "no output stream was specified"); | |
197 | } | ||
198 | 6 | this->writeGrids(*mImpl->mOutputStream, grids, metadata); | |
199 | 6 | } | |
200 | |||
201 | |||
202 | void | ||
203 | 6 | Stream::writeGrids(std::ostream& os, const GridCPtrVec& grids, const MetaMap& metadata) const | |
204 | { | ||
205 | 6 | Archive::write(os, grids, /*seekable=*/false, metadata); | |
206 | 6 | } | |
207 | |||
208 | |||
209 | //////////////////////////////////////// | ||
210 | |||
211 | |||
212 | MetaMap::Ptr | ||
213 | 2 | Stream::getMetadata() const | |
214 | { | ||
215 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | MetaMap::Ptr result; |
216 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (mImpl->mFile) { |
217 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
4 | result = mImpl->mFile->getMetadata(); |
218 | ✗ | } else if (mImpl->mMeta) { | |
219 | // Return a deep copy of the file-level metadata | ||
220 | // that was read when this object was constructed. | ||
221 | ✗ | result.reset(new MetaMap(*mImpl->mMeta)); | |
222 | } | ||
223 | 2 | return result; | |
224 | } | ||
225 | |||
226 | |||
227 | GridPtrVecPtr | ||
228 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Stream::getGrids() |
229 | { | ||
230 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (mImpl->mFile) { |
231 | 3 | return mImpl->mFile->getGrids(); | |
232 | } | ||
233 | return mImpl->mGrids; | ||
234 | } | ||
235 | |||
236 | } // namespace io | ||
237 | } // namespace OPENVDB_VERSION_NAME | ||
238 | } // namespace openvdb | ||
239 |