ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
CompressedVectorReaderImpl.cpp
Go to the documentation of this file.
1 /*
2  * Original work Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
3  * Modified work Copyright 2018 - 2020 Andy Maloney <asmaloney@gmail.com>
4  *
5  * Permission is hereby granted, free of charge, to any person or organization
6  * obtaining a copy of the software and accompanying documentation covered by
7  * this license (the "Software") to use, reproduce, display, distribute,
8  * execute, and transmit the Software, and to prepare derivative works of the
9  * Software, and to permit third-parties to whom the Software is furnished to
10  * do so, all subject to the following:
11  *
12  * The copyright notices in the Software and this entire statement, including
13  * the above license grant, this restriction and the following disclaimer,
14  * must be included in all copies of the Software, in whole or in part, and
15  * all derivative works of the Software, unless such copies or derivative
16  * works are solely in the form of machine-executable object code generated by
17  * a source language processor.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
22  * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
23  * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
24  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25  * DEALINGS IN THE SOFTWARE.
26  */
27 
29 #include "CheckedFile.h"
31 #include "ImageFileImpl.h"
32 #include "Packet.h"
33 #include "SectionHeaders.h"
34 #include "SourceDestBufferImpl.h"
35 
36 namespace e57
37 {
38  CompressedVectorReaderImpl::CompressedVectorReaderImpl( std::shared_ptr<CompressedVectorNodeImpl> cvi,
39  std::vector<SourceDestBuffer> &dbufs ) :
40  isOpen_( false ), // set to true when succeed below
41  cVector_( cvi )
42  {
43 #ifdef E57_MAX_VERBOSE
44  std::cout << "CompressedVectorReaderImpl() called" << std::endl; //???
45 #endif
46  checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
47 
53 
55  if ( dbufs.empty() )
56  {
58  "imageFileName=" + cVector_->imageFileName() + " cvPathName=" + cVector_->pathName() );
59  }
60 
63  proto_ = cVector_->getPrototype();
64 
66  setBuffers( dbufs );
67 
70  for ( unsigned i = 0; i < dbufs_.size(); i++ )
71  {
72  std::vector<SourceDestBuffer> theDbuf;
73  theDbuf.push_back( dbufs.at( i ) );
74 
75  std::shared_ptr<Decoder> decoder = Decoder::DecoderFactory( i, cVector_.get(), theDbuf, ustring() );
76 
79  NodeImplSharedPtr readNode = proto_->get( dbufs.at( i ).pathName() );
80  uint64_t bytestreamNumber = 0;
81  if ( !proto_->findTerminalPosition( readNode, bytestreamNumber ) )
82  {
83  throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "dbufIndex=" + toString( i ) );
84  }
85 
86  channels_.emplace_back( dbufs.at( i ), decoder, static_cast<unsigned>( bytestreamNumber ),
87  cVector_->childCount() );
88  }
89 
90  recordCount_ = 0;
91 
93  maxRecordCount_ = cvi->childCount();
94 
95  ImageFileImplSharedPtr imf( cVector_->destImageFile_ );
96 
97  //??? what if fault in this constructor?
98  cache_ = new PacketReadCache( imf->file_, 32 );
99 
101  CompressedVectorSectionHeader sectionHeader;
102  uint64_t sectionLogicalStart = cVector_->getBinarySectionLogicalStart();
103  if ( sectionLogicalStart == 0 )
104  {
105  //??? should have caught this before got here, in XML read, get this if CV
106  // wasn't written to
107  // by writer.
109  "imageFileName=" + cVector_->imageFileName() + " cvPathName=" + cVector_->pathName() );
110  }
111  imf->file_->seek( sectionLogicalStart, CheckedFile::Logical );
112  imf->file_->read( reinterpret_cast<char *>( &sectionHeader ), sizeof( sectionHeader ) );
113 
114 #ifdef E57_DEBUG
115  sectionHeader.verify( imf->file_->length( CheckedFile::Physical ) );
116 #endif
117 
119  sectionEndLogicalOffset_ = sectionLogicalStart + sectionHeader.sectionLogicalLength;
120 
122  uint64_t dataLogicalOffset = imf->file_->physicalToLogical( sectionHeader.dataPhysicalOffset );
123 
126  {
127  char *anyPacket = nullptr;
128  std::unique_ptr<PacketLock> packetLock = cache_->lock( dataLogicalOffset, anyPacket );
129 
130  auto dpkt = reinterpret_cast<DataPacket *>( anyPacket );
131 
133  if ( dpkt->header.packetType != DATA_PACKET )
134  {
135  throw E57_EXCEPTION2( E57_ERROR_BAD_CV_PACKET, "packetType=" + toString( dpkt->header.packetType ) );
136  }
137 
139  for ( auto &channel : channels_ )
140  {
141  channel.currentPacketLogicalOffset = dataLogicalOffset;
142  channel.currentBytestreamBufferIndex = 0;
143  channel.currentBytestreamBufferLength = dpkt->getBytestreamBufferLength( channel.bytestreamNumber );
144  }
145  }
146 
149  imf->incrReaderCount();
150 
152  isOpen_ = true;
153  }
154 
156  {
157 #ifdef E57_MAX_VERBOSE
158  std::cout << "~CompressedVectorReaderImpl() called" << std::endl; //???
159  // dump(4);
160 #endif
161 
162  if ( isOpen_ )
163  {
164  try
165  {
166  close();
167  }
168  catch ( ... )
169  {
170  //??? report?
171  }
172  }
173  }
174 
175  void CompressedVectorReaderImpl::setBuffers( std::vector<SourceDestBuffer> &dbufs )
176  {
179 
181  proto_->checkBuffers( dbufs, true );
182 
185  if ( !dbufs_.empty() )
186  {
187  if ( dbufs_.size() != dbufs.size() )
188  {
190  "oldSize=" + toString( dbufs_.size() ) + " newSize=" + toString( dbufs.size() ) );
191  }
192  for ( size_t i = 0; i < dbufs_.size(); i++ )
193  {
194  std::shared_ptr<SourceDestBufferImpl> oldBuf = dbufs_[i].impl();
195  std::shared_ptr<SourceDestBufferImpl> newBuf = dbufs[i].impl();
196 
198  oldBuf->checkCompatible( newBuf );
199  }
200  }
201 
202  dbufs_ = dbufs;
203  }
204 
205  unsigned CompressedVectorReaderImpl::read( std::vector<SourceDestBuffer> &dbufs )
206  {
209 
210  checkReaderOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
211 
213  setBuffers( dbufs );
214 
215  return ( read() );
216  }
217 
219  {
220 #ifdef E57_MAX_VERBOSE
221  std::cout << "CompressedVectorReaderImpl::read() called" << std::endl; //???
222 #endif
223  checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
224  checkReaderOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
225 
227  for ( auto &dbuf : dbufs_ )
228  {
229  dbuf.impl()->rewind();
230  }
231 
235  for ( auto &channel : channels_ )
236  {
237  channel.decoder->inputProcess( nullptr, 0 );
238  }
239 
242  while ( true )
243  {
247  uint64_t earliestPacketLogicalOffset = earliestPacketNeededForInput();
248 
250  if ( earliestPacketLogicalOffset == E57_UINT64_MAX )
251  {
252  break;
253  }
254 
256  feedPacketToDecoders( earliestPacketLogicalOffset );
257  }
258 
260  unsigned outputCount = 0;
261  for ( unsigned i = 0; i < channels_.size(); i++ )
262  {
263  DecodeChannel *chan = &channels_[i];
264  if ( i == 0 )
265  {
266  outputCount = chan->dbuf.impl()->nextIndex();
267  }
268  else
269  {
270  if ( outputCount != chan->dbuf.impl()->nextIndex() )
271  {
272  throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "outputCount=" + toString( outputCount ) + " nextIndex=" +
273  toString( chan->dbuf.impl()->nextIndex() ) );
274  }
275  }
276  }
277 
279  return outputCount;
280  }
281 
282  uint64_t CompressedVectorReaderImpl::earliestPacketNeededForInput() const
283  {
284  uint64_t earliestPacketLogicalOffset = E57_UINT64_MAX;
285 #ifdef E57_MAX_VERBOSE
286  unsigned earliestChannel = 0;
287 #endif
288 
289  for ( unsigned i = 0; i < channels_.size(); i++ )
290  {
291  const DecodeChannel *chan = &channels_[i];
292 
295  if ( !chan->isOutputBlocked() && !chan->inputFinished )
296  {
298  if ( chan->currentPacketLogicalOffset < earliestPacketLogicalOffset )
299  {
300  earliestPacketLogicalOffset = chan->currentPacketLogicalOffset;
301 #ifdef E57_MAX_VERBOSE
302  earliestChannel = i;
303 #endif
304  }
305  }
306  }
307 #ifdef E57_MAX_VERBOSE
308  if ( earliestPacketLogicalOffset == E57_UINT64_MAX )
309  {
310  std::cout << "earliestPacketNeededForInput returning none found" << std::endl;
311  }
312  else
313  {
314  std::cout << "earliestPacketNeededForInput returning " << earliestPacketLogicalOffset << " for channel["
315  << earliestChannel << "]" << std::endl;
316  }
317 #endif
318  return earliestPacketLogicalOffset;
319  }
320 
321  DataPacket *CompressedVectorReaderImpl::dataPacket( uint64_t inLogicalOffset ) const
322  {
323  char *packet = nullptr;
324 
325  std::unique_ptr<PacketLock> packetLock = cache_->lock( inLogicalOffset, packet );
326 
327  return reinterpret_cast<DataPacket *>( packet );
328  }
329 
330  inline bool _alreadyReadPacket( const DecodeChannel &channel, uint64_t currentPacketLogicalOffset )
331  {
332  return ( ( channel.currentPacketLogicalOffset != currentPacketLogicalOffset ) || channel.isOutputBlocked() );
333  }
334 
335  void CompressedVectorReaderImpl::feedPacketToDecoders( uint64_t currentPacketLogicalOffset )
336  {
337  // Get packet at currentPacketLogicalOffset into memory.
338  auto dpkt = dataPacket( currentPacketLogicalOffset );
339 
340  // Double check that have a data packet. Should have already determined
341  // this.
342  if ( dpkt->header.packetType != DATA_PACKET )
343  {
344  throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "packetType=" + toString( dpkt->header.packetType ) );
345  }
346 
347  // Read earliest packet into cache and send data to decoders with unblocked
348  // output
349 
350  bool anyChannelHasExhaustedPacket = false;
351  uint64_t nextPacketLogicalOffset = E57_UINT64_MAX;
352 
353  // Feed bytestreams to channels with unblocked output that are reading from
354  // this packet
355  for ( DecodeChannel &channel : channels_ )
356  {
357  // Skip channels that have already read this packet.
358  if ( _alreadyReadPacket( channel, currentPacketLogicalOffset ) )
359  {
360  continue;
361  }
362 
363  // Get bytestream buffer for this channel from packet
364  unsigned int bsbLength = 0;
365  const char *bsbStart = dpkt->getBytestream( channel.bytestreamNumber, bsbLength );
366 
367  // Double check we are not off end of buffer
368  if ( channel.currentBytestreamBufferIndex > bsbLength )
369  {
371  "currentBytestreamBufferIndex =" + toString( channel.currentBytestreamBufferIndex ) +
372  " bsbLength=" + toString( bsbLength ) );
373  }
374 
375  // Calc where we are in the buffer
376  const char *uneatenStart = &bsbStart[channel.currentBytestreamBufferIndex];
377  const size_t uneatenLength = bsbLength - channel.currentBytestreamBufferIndex;
378 
379  if ( &uneatenStart[uneatenLength] > &bsbStart[bsbLength] )
380  {
381  throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "uneatenLength=" + toString( uneatenLength ) +
382  " bsbLength=" + toString( bsbLength ) );
383  }
384 
385  // Feed into decoder
386  const size_t bytesProcessed = channel.decoder->inputProcess( uneatenStart, uneatenLength );
387 
388 #ifdef E57_MAX_VERBOSE
389  std::cout << " stream[" << channel.bytestreamNumber << "]: feeding decoder " << uneatenLength << " bytes"
390  << std::endl;
391 
392  if ( uneatenLength == 0 )
393  {
394  channel.dump( 8 );
395  }
396 
397  std::cout << " stream[" << channel.bytestreamNumber << "]: bytesProcessed=" << bytesProcessed << std::endl;
398 #endif
399 
400  // Adjust counts of bytestream location
401  channel.currentBytestreamBufferIndex += bytesProcessed;
402 
403  // Check if this channel has exhausted its bytestream buffer in this
404  // packet
405  if ( channel.isInputBlocked() )
406  {
407 #ifdef E57_MAX_VERBOSE
408  std::cout << " stream[" << channel.bytestreamNumber << "] has exhausted its input in current packet"
409  << std::endl;
410 #endif
411  anyChannelHasExhaustedPacket = true;
412  nextPacketLogicalOffset = currentPacketLogicalOffset + dpkt->header.packetLogicalLengthMinus1 + 1;
413  }
414  }
415 
416  // Skip over any index or empty packets to next data packet.
417  nextPacketLogicalOffset = findNextDataPacket( nextPacketLogicalOffset );
418 
419  // If no channel is exhausted, we're done
420  if ( !anyChannelHasExhaustedPacket )
421  {
422  return;
423  }
424 
425  // Some channel has exhausted this packet, so find next data packet and
426  // update currentPacketLogicalOffset for all interested channels.
427 
428  if ( nextPacketLogicalOffset < E57_UINT64_MAX )
429  { //??? huh?
430  // Get packet at nextPacketLogicalOffset into memory.
431  dpkt = dataPacket( nextPacketLogicalOffset );
432 
433  // Got a data packet, update the channels with exhausted input
434  for ( DecodeChannel &channel : channels_ )
435  {
436  // Skip channels that have already read this packet.
437  if ( _alreadyReadPacket( channel, currentPacketLogicalOffset ) )
438  {
439  continue;
440  }
441 
442  channel.currentPacketLogicalOffset = nextPacketLogicalOffset;
443  channel.currentBytestreamBufferIndex = 0;
444 
445  // It is OK if the next packet doesn't contain any data for this
446  // channel, will skip packet on next iter of loop
447  channel.currentBytestreamBufferLength = dpkt->getBytestreamBufferLength( channel.bytestreamNumber );
448 
449 #ifdef E57_MAX_VERBOSE
450  std::cout << " set new stream buffer for channel[" << channel.bytestreamNumber
451  << "], length=" << channel.currentBytestreamBufferLength << std::endl;
452 #endif
453  // ??? perform flush if new packet flag set?
454  }
455  }
456  else
457  {
458  // Reached end without finding data packet, mark exhausted channels as
459  // finished
460 #ifdef E57_MAX_VERBOSE
461  std::cout << " at end of data packets" << std::endl;
462 #endif
463  if ( nextPacketLogicalOffset >= sectionEndLogicalOffset_ )
464  {
465  for ( DecodeChannel &channel : channels_ )
466  {
467  // Skip channels that have already read this packet.
468  if ( _alreadyReadPacket( channel, currentPacketLogicalOffset ) )
469  {
470  continue;
471  }
472 
473 #ifdef E57_MAX_VERBOSE
474  std::cout << " Marking channel[" << channel.bytestreamNumber << "] as finished" << std::endl;
475 #endif
476  channel.inputFinished = true;
477  }
478  }
479  }
480  }
481 
482  uint64_t CompressedVectorReaderImpl::findNextDataPacket( uint64_t nextPacketLogicalOffset )
483  {
484 #ifdef E57_MAX_VERBOSE
485  std::cout << " searching for next data packet, nextPacketLogicalOffset=" << nextPacketLogicalOffset
486  << " sectionEndLogicalOffset=" << sectionEndLogicalOffset_ << std::endl;
487 #endif
488 
491  while ( nextPacketLogicalOffset < sectionEndLogicalOffset_ )
492  {
493  char *anyPacket = nullptr;
494 
495  std::unique_ptr<PacketLock> packetLock = cache_->lock( nextPacketLogicalOffset, anyPacket );
496 
498  auto dpkt = reinterpret_cast<const DataPacket *>( anyPacket );
499 
500  if ( dpkt->header.packetType == DATA_PACKET )
501  {
502 #ifdef E57_MAX_VERBOSE
503  std::cout << " Found next data packet at nextPacketLogicalOffset=" << nextPacketLogicalOffset << std::endl;
504 #endif
505  return nextPacketLogicalOffset;
506  }
507 
510  nextPacketLogicalOffset += dpkt->header.packetLogicalLengthMinus1 + 1;
511  }
512 
514  return E57_UINT64_MAX;
515  }
516 
517  void CompressedVectorReaderImpl::seek( uint64_t /*recordNumber*/ )
518  {
519  checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
520 
523  }
524 
526  {
529  return ( isOpen_ );
530  }
531 
532  std::shared_ptr<CompressedVectorNodeImpl> CompressedVectorReaderImpl::compressedVectorNode() const
533  {
534  return ( cVector_ );
535  }
536 
538  {
540  ImageFileImplSharedPtr imf( cVector_->destImageFile_ );
541  imf->decrReaderCount();
542 
543  checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
544 
546  if ( !isOpen_ )
547  {
548  return;
549  }
550 
552  channels_.clear();
553 
554  delete cache_;
555  cache_ = nullptr;
556 
557  isOpen_ = false;
558  }
559 
560  void CompressedVectorReaderImpl::checkImageFileOpen( const char *srcFileName, int srcLineNumber,
561  const char *srcFunctionName ) const
562  {
563  // unimplemented...
564  }
565 
566  void CompressedVectorReaderImpl::checkReaderOpen( const char *srcFileName, int srcLineNumber,
567  const char *srcFunctionName ) const
568  {
569  if ( !isOpen_ )
570  {
571  throw E57Exception( E57_ERROR_READER_NOT_OPEN,
572  "imageFileName=" + cVector_->imageFileName() + " cvPathName=" + cVector_->pathName(),
573  srcFileName, srcLineNumber, srcFunctionName );
574  }
575  }
576 
577  void CompressedVectorReaderImpl::dump( int indent, std::ostream &os )
578  {
579  os << space( indent ) << "isOpen:" << isOpen_ << std::endl;
580 
581  for ( unsigned i = 0; i < dbufs_.size(); i++ )
582  {
583  os << space( indent ) << "dbufs[" << i << "]:" << std::endl;
584  dbufs_[i].dump( indent + 4, os );
585  }
586 
587  os << space( indent ) << "cVector:" << std::endl;
588  cVector_->dump( indent + 4, os );
589 
590  os << space( indent ) << "proto:" << std::endl;
591  proto_->dump( indent + 4, os );
592 
593  for ( unsigned i = 0; i < channels_.size(); i++ )
594  {
595  os << space( indent ) << "channels[" << i << "]:" << std::endl;
596  channels_[i].dump( indent + 4, os );
597  }
598 
599  os << space( indent ) << "recordCount: " << recordCount_ << std::endl;
600  os << space( indent ) << "maxRecordCount: " << maxRecordCount_ << std::endl;
601  os << space( indent ) << "sectionEndLogicalOffset: " << sectionEndLogicalOffset_ << std::endl;
602  }
603 
604 }
#define E57_EXCEPTION2(ecode, context)
Definition: Common.h:68
#define E57_EXCEPTION1(ecode)
!! inline these rather than macros?
Definition: Common.h:66
CompressedVectorReaderImpl(std::shared_ptr< CompressedVectorNodeImpl > ni, std::vector< SourceDestBuffer > &dbufs)
void dump(int indent=0, std::ostream &os=std::cout)
std::shared_ptr< CompressedVectorNodeImpl > compressedVectorNode() const
static std::shared_ptr< Decoder > DecoderFactory(unsigned bytestreamNumber, const CompressedVectorNodeImpl *cVector, std::vector< SourceDestBuffer > &dbufs, const ustring &codecPath)
Definition: Decoder.cpp:41
std::unique_ptr< PacketLock > lock(uint64_t packetLogicalOffset, char *&pkt)
Definition: Packet.cpp:85
QTextStream & endl(QTextStream &stream)
Definition: QtCompat.h:718
bool _alreadyReadPacket(const DecodeChannel &channel, uint64_t currentPacketLogicalOffset)
std::shared_ptr< class NodeImpl > NodeImplSharedPtr
Definition: Common.h:190
std::shared_ptr< class ImageFileImpl > ImageFileImplSharedPtr
Definition: Common.h:188
@ E57_ERROR_BUFFERS_NOT_COMPATIBLE
SourceDestBuffers not compatible with previously given ones.
Definition: E57Exception.h:92
@ E57_ERROR_INTERNAL
An unrecoverable inconsistent internal state was detected.
Definition: E57Exception.h:56
@ E57_ERROR_BAD_API_ARGUMENT
bad API function argument provided by user
Definition: E57Exception.h:59
@ E57_ERROR_BAD_CV_PACKET
a CompressedVector binary packet was bad
Definition: E57Exception.h:45
@ E57_ERROR_NOT_IMPLEMENTED
functionality not implemented
Definition: E57Exception.h:84
@ E57_ERROR_READER_NOT_OPEN
CompressedVectorReader is no longer open.
Definition: E57Exception.h:87
@ DATA_PACKET
Definition: Packet.h:44
std::string ustring
UTF-8 encodeded Unicode string.
Definition: E57Format.h:54
std::string toString(T x)
Definition: Common.h:80
std::string space(size_t n)
Definition: Common.h:73
void verify(uint64_t filePhysicalSize=0)
SourceDestBuffer dbuf
Definition: DecodeChannel.h:37
bool isOutputBlocked() const
uint64_t currentPacketLogicalOffset
Definition: DecodeChannel.h:41