1#pragma once
2
3/*
4Open Asset Import Library (assimp)
5----------------------------------------------------------------------
6
7Copyright (c) 2006-2017, assimp team
8
9All rights reserved.
10
11Redistribution and use of this software in source and binary forms,
12with or without modification, are permitted provided that the
13following conditions are met:
14
15* Redistributions of source code must retain the above
16copyright notice, this list of conditions and the
17following disclaimer.
18
19* Redistributions in binary form must reproduce the above
20copyright notice, this list of conditions and the
21following disclaimer in the documentation and/or other
22materials provided with the distribution.
23
24* Neither the name of the assimp team, nor the names of its
25contributors may be used to endorse or promote products
26derived from this software without specific prior
27written permission of the assimp team.
28
29THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40
41----------------------------------------------------------------------
42*/
43
44#include <assimp/types.h>
45#include <assimp/IOStream.hpp>
46#include "ParsingUtils.h"
47
48#include <vector>
49
50namespace Assimp {
51
52// ---------------------------------------------------------------------------
53/**
54 * Implementation of a cached stream buffer.
55 */
56template<class T>
57class IOStreamBuffer {
58public:
59 /// @brief The class constructor.
60 IOStreamBuffer( size_t cache = 4096 * 4096 );
61
62 /// @brief The class destructor.
63 ~IOStreamBuffer();
64
65 /// @brief Will open the cached access for a given stream.
66 /// @param stream The stream to cache.
67 /// @return true if successful.
68 bool open( IOStream *stream );
69
70 /// @brief Will close the cached access.
71 /// @return true if successful.
72 bool close();
73
74 /// @brief Returns the file-size.
75 /// @return The file-size.
76 size_t size() const;
77
78 /// @brief Returns the cache size.
79 /// @return The cache size.
80 size_t cacheSize() const;
81
82 /// @brief Will read the next block.
83 /// @return true if successful.
84 bool readNextBlock();
85
86 /// @brief Returns the number of blocks to read.
87 /// @return The number of blocks.
88 size_t getNumBlocks() const;
89
90 /// @brief Returns the current block index.
91 /// @return The current block index.
92 size_t getCurrentBlockIndex() const;
93
94 /// @brief Returns the current file pos.
95 /// @return The current file pos.
96 size_t getFilePos() const;
97
98 /// @brief Will read the next line.
99 /// @param buffer The buffer for the next line.
100 /// @return true if successful.
101 bool getNextDataLine( std::vector<T> &buffer, T continuationToken );
102
103 /// @brief Will read the next line ascii or binary end line char.
104 /// @param buffer The buffer for the next line.
105 /// @return true if successful.
106 bool getNextLine(std::vector<T> &buffer);
107
108 /// @brief Will read the next block.
109 /// @param buffer The buffer for the next block.
110 /// @return true if successful.
111 bool getNextBlock( std::vector<T> &buffer );
112
113private:
114 IOStream *m_stream;
115 size_t m_filesize;
116 size_t m_cacheSize;
117 size_t m_numBlocks;
118 size_t m_blockIdx;
119 std::vector<T> m_cache;
120 size_t m_cachePos;
121 size_t m_filePos;
122};
123
124template<class T>
125inline
126IOStreamBuffer<T>::IOStreamBuffer( size_t cache )
127: m_stream( nullptr )
128, m_filesize( 0 )
129, m_cacheSize( cache )
130, m_numBlocks( 0 )
131, m_blockIdx( 0 )
132, m_cachePos( 0 )
133, m_filePos( 0 ) {
134 m_cache.resize( cache );
135 std::fill( m_cache.begin(), m_cache.end(), '\n' );
136}
137
138template<class T>
139inline
140IOStreamBuffer<T>::~IOStreamBuffer() {
141 // empty
142}
143
144template<class T>
145inline
146bool IOStreamBuffer<T>::open( IOStream *stream ) {
147 // file still opened!
148 if ( nullptr != m_stream ) {
149 return false;
150 }
151
152 // Invalid stream pointer
153 if ( nullptr == stream ) {
154 return false;
155 }
156
157 m_stream = stream;
158 m_filesize = m_stream->FileSize();
159 if ( m_filesize == 0 ) {
160 return false;
161 }
162 if ( m_filesize < m_cacheSize ) {
163 m_cacheSize = m_filesize;
164 }
165
166 m_numBlocks = m_filesize / m_cacheSize;
167 if ( ( m_filesize % m_cacheSize ) > 0 ) {
168 m_numBlocks++;
169 }
170
171 return true;
172}
173
174template<class T>
175inline
176bool IOStreamBuffer<T>::close() {
177 if ( nullptr == m_stream ) {
178 return false;
179 }
180
181 // init counters and state vars
182 m_stream = nullptr;
183 m_filesize = 0;
184 m_numBlocks = 0;
185 m_blockIdx = 0;
186 m_cachePos = 0;
187 m_filePos = 0;
188
189 return true;
190}
191
192template<class T>
193inline
194size_t IOStreamBuffer<T>::size() const {
195 return m_filesize;
196}
197
198template<class T>
199inline
200size_t IOStreamBuffer<T>::cacheSize() const {
201 return m_cacheSize;
202}
203
204template<class T>
205inline
206bool IOStreamBuffer<T>::readNextBlock() {
207 m_stream->Seek( m_filePos, aiOrigin_SET );
208 size_t readLen = m_stream->Read( &m_cache[ 0 ], sizeof( T ), m_cacheSize );
209 if ( readLen == 0 ) {
210 return false;
211 }
212 if ( readLen < m_cacheSize ) {
213 m_cacheSize = readLen;
214 }
215 m_filePos += m_cacheSize;
216 m_cachePos = 0;
217 m_blockIdx++;
218
219 return true;
220}
221
222template<class T>
223inline
224size_t IOStreamBuffer<T>::getNumBlocks() const {
225 return m_numBlocks;
226}
227
228template<class T>
229inline
230size_t IOStreamBuffer<T>::getCurrentBlockIndex() const {
231 return m_blockIdx;
232}
233
234template<class T>
235inline
236size_t IOStreamBuffer<T>::getFilePos() const {
237 return m_filePos;
238}
239
240template<class T>
241inline
242bool IOStreamBuffer<T>::getNextDataLine( std::vector<T> &buffer, T continuationToken ) {
243 buffer.resize( m_cacheSize );
244 if ( m_cachePos == m_cacheSize || 0 == m_filePos ) {
245 if ( !readNextBlock() ) {
246 return false;
247 }
248 }
249
250 bool continuationFound( false ), endOfDataLine( false );
251 size_t i = 0;
252 while ( !endOfDataLine ) {
253 if ( continuationToken == m_cache[ m_cachePos ] ) {
254 continuationFound = true;
255 ++m_cachePos;
256 }
257 if ( IsLineEnd( m_cache[ m_cachePos ] ) ) {
258 if ( !continuationFound ) {
259 // the end of the data line
260 break;
261 } else {
262 // skip line end
263 while ( m_cache[m_cachePos] != '\n') {
264 ++m_cachePos;
265 }
266 ++m_cachePos;
267 continuationFound = false;
268 }
269 }
270
271 buffer[ i ] = m_cache[ m_cachePos ];
272 m_cachePos++;
273 i++;
274 if ( m_cachePos >= m_cacheSize ) {
275 if ( !readNextBlock() ) {
276 return false;
277 }
278 }
279 }
280
281 buffer[ i ] = '\n';
282 m_cachePos++;
283
284 return true;
285}
286
287static
288inline
289bool isEndOfCache( size_t pos, size_t cacheSize ) {
290 return ( pos == cacheSize );
291}
292
293template<class T>
294inline
295bool IOStreamBuffer<T>::getNextLine(std::vector<T> &buffer) {
296 buffer.resize(m_cacheSize);
297 if ( isEndOfCache( m_cachePos, m_cacheSize ) || 0 == m_filePos) {
298 if (!readNextBlock()) {
299 return false;
300 }
301 }
302
303 if (IsLineEnd(m_cache[m_cachePos])) {
304 // skip line end
305 while (m_cache[m_cachePos] != '\n') {
306 ++m_cachePos;
307 }
308 ++m_cachePos;
309 if ( isEndOfCache( m_cachePos, m_cacheSize ) ) {
310 if ( !readNextBlock() ) {
311 return false;
312 }
313 }
314 }
315
316 size_t i = 0;
317 while (!IsLineEnd(m_cache[ m_cachePos ])) {
318 buffer[i] = m_cache[ m_cachePos ];
319 m_cachePos++;
320 i++;
321 if (m_cachePos >= m_cacheSize) {
322 if (!readNextBlock()) {
323 return false;
324 }
325 }
326 }
327 buffer[i] = '\n';
328 m_cachePos++;
329
330 return true;
331}
332
333template<class T>
334inline
335bool IOStreamBuffer<T>::getNextBlock( std::vector<T> &buffer) {
336 //just return the last blockvalue if getNextLine was used before
337 if ( m_cachePos != 0) {
338 buffer = std::vector<T>(m_cache.begin() + m_cachePos, m_cache.end());
339 m_cachePos = 0;
340 }
341 else {
342 if ( !readNextBlock() )
343 return false;
344
345 buffer = std::vector<T>(m_cache.begin(), m_cache.end());
346 }
347 return true;
348}
349
350} // !ns Assimp
351