ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
CompressedVectorWriterImpl.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 
28 #include <cmath>
29 #include <numeric>
30 
31 #include "CheckedFile.h"
34 #include "ImageFileImpl.h"
35 #include "SectionHeaders.h"
36 #include "SourceDestBufferImpl.h"
37 
38 namespace e57
39 {
41  {
42  bool operator()( const std::shared_ptr<Encoder> &lhs, const std::shared_ptr<Encoder> &rhs ) const
43  {
44  return ( lhs->bytestreamNumber() < rhs->bytestreamNumber() );
45  }
46  };
47 
48  CompressedVectorWriterImpl::CompressedVectorWriterImpl( std::shared_ptr<CompressedVectorNodeImpl> ni,
49  std::vector<SourceDestBuffer> &sbufs ) :
50  cVector_( ni ), isOpen_( false ) // set to true when succeed below
51  {
52  //??? check if cvector already been written (can't write twice)
53 
55  if ( sbufs.empty() )
56  {
58  "imageFileName=" + cVector_->imageFileName() + " cvPathName=" + cVector_->pathName() );
59  }
60 
63  proto_ = cVector_->getPrototype();
64 
66  setBuffers( sbufs ); //??? copy code here?
67 
70  for ( unsigned i = 0; i < sbufs_.size(); i++ )
71  {
73  std::vector<SourceDestBuffer> vTemp;
74  vTemp.push_back( sbufs_.at( i ) );
75 
76  ustring codecPath = sbufs_.at( i ).pathName();
77 
80  NodeImplSharedPtr readNode = proto_->get( sbufs.at( i ).pathName() );
81  uint64_t bytestreamNumber = 0;
82  if ( !proto_->findTerminalPosition( readNode, bytestreamNumber ) )
83  {
84  throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "sbufIndex=" + toString( i ) );
85  }
86 
89  bytestreams_.push_back(
90  Encoder::EncoderFactory( static_cast<unsigned>( bytestreamNumber ), cVector_, vTemp, codecPath ) );
91  }
92 
95  sort( bytestreams_.begin(), bytestreams_.end(), SortByBytestreamNumber() );
96 #ifdef E57_MAX_DEBUG
98  for ( unsigned i = 0; i < bytestreams_.size(); i++ )
99  {
100  if ( bytestreams_.at( i )->bytestreamNumber() != i )
101  {
102  throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "bytestreamIndex=" + toString( i ) + " bytestreamNumber=" +
103  toString( bytestreams_.at( i )->bytestreamNumber() ) );
104  }
105  }
106 #endif
107 
108  ImageFileImplSharedPtr imf( ni->destImageFile_ );
109 
113  sectionHeaderLogicalStart_ = imf->allocateSpace( sizeof( CompressedVectorSectionHeader ), true );
114 
115  sectionLogicalLength_ = 0;
116  dataPhysicalOffset_ = 0;
117  topIndexPhysicalOffset_ = 0;
118  recordCount_ = 0;
119  dataPacketsCount_ = 0;
120  indexPacketsCount_ = 0;
121 
124  imf->incrWriterCount();
125 
127  isOpen_ = true;
128  }
129 
131  {
132 #ifdef E57_MAX_VERBOSE
133  std::cout << "~CompressedVectorWriterImpl() called" << std::endl; //???
134 #endif
135 
136  try
137  {
138  if ( isOpen_ )
139  {
140  close();
141  }
142  }
143  catch ( ... )
144  {
145  //??? report?
146  }
147  }
148 
150  {
151 #ifdef E57_MAX_VERBOSE
152  std::cout << "CompressedVectorWriterImpl::close() called" << std::endl; //???
153 #endif
154  ImageFileImplSharedPtr imf( cVector_->destImageFile_ );
155 
157  imf->decrWriterCount();
158 
159  checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
161 
162  if ( !isOpen_ )
163  {
164  return;
165  }
166 
169  isOpen_ = false;
170 
175  flush();
176  while ( totalOutputAvailable() > 0 )
177  {
178  packetWrite();
179  flush();
180  }
181 
184  sectionLogicalLength_ = imf->unusedLogicalStart_ - sectionHeaderLogicalStart_;
185 #ifdef E57_MAX_VERBOSE
186  std::cout << " sectionLogicalLength_=" << sectionLogicalLength_ << std::endl; //???
187 #endif
188 
191  header.sectionLogicalLength = sectionLogicalLength_;
192  header.dataPhysicalOffset = dataPhysicalOffset_;
193  header.indexPhysicalOffset = topIndexPhysicalOffset_;
195 #ifdef E57_MAX_VERBOSE
196  std::cout << " CompressedVectorSectionHeader:" << std::endl;
197  header.dump( 4 ); //???
198 #endif
199 #ifdef E57_DEBUG
201  header.verify( imf->file_->length( CheckedFile::Physical ) );
202 #endif
203 
205  imf->file_->seek( sectionHeaderLogicalStart_ );
206  imf->file_->write( reinterpret_cast<char *>( &header ), sizeof( header ) );
207 
209  cVector_->setRecordCount( recordCount_ );
210  cVector_->setBinarySectionLogicalStart( sectionHeaderLogicalStart_ );
211 
213  bytestreams_.clear();
214 
215 #ifdef E57_MAX_VERBOSE
216  std::cout << " CompressedVectorWriter:" << std::endl;
217  dump( 4 );
218 #endif
219  }
220 
222  {
225  return isOpen_;
226  }
227 
228  std::shared_ptr<CompressedVectorNodeImpl> CompressedVectorWriterImpl::compressedVectorNode() const
229  {
230  return cVector_;
231  }
232 
233  void CompressedVectorWriterImpl::setBuffers( std::vector<SourceDestBuffer> &sbufs )
234  {
236 
239  if ( !sbufs_.empty() )
240  {
241  if ( sbufs_.size() != sbufs.size() )
242  {
244  "oldSize=" + toString( sbufs_.size() ) + " newSize=" + toString( sbufs.size() ) );
245  }
246 
247  for ( size_t i = 0; i < sbufs_.size(); ++i )
248  {
249  std::shared_ptr<SourceDestBufferImpl> oldbuf = sbufs_[i].impl();
250  std::shared_ptr<SourceDestBufferImpl> newBuf = sbufs[i].impl();
251 
253  oldbuf->checkCompatible( newBuf );
254  }
255  }
256 
260  proto_->checkBuffers( sbufs, false );
261 
262  sbufs_ = sbufs;
263  }
264 
265  void CompressedVectorWriterImpl::write( std::vector<SourceDestBuffer> &sbufs, const size_t requestedRecordCount )
266  {
269 
270  setBuffers( sbufs );
271  write( requestedRecordCount );
272  }
273 
274  void CompressedVectorWriterImpl::write( const size_t requestedRecordCount )
275  {
276 #ifdef E57_MAX_VERBOSE
277  std::cout << "CompressedVectorWriterImpl::write() called" << std::endl; //???
278 #endif
279  checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
280  checkWriterOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
281 
283  if ( requestedRecordCount > sbufs_.at( 0 ).impl()->capacity() )
284  {
286  "requested=" + toString( requestedRecordCount ) +
287  " capacity=" + toString( sbufs_.at( 0 ).impl()->capacity() ) + " imageFileName=" +
288  cVector_->imageFileName() + " cvPathName=" + cVector_->pathName() );
289  }
290 
292  for ( auto &sbuf : sbufs_ )
293  {
294  sbuf.impl()->rewind();
295  }
296 
298  uint64_t endRecordIndex = recordCount_ + requestedRecordCount;
299  while ( true )
300  {
302  uint64_t totalRecordCount = 0;
303  for ( auto &bytestream : bytestreams_ )
304  {
305  totalRecordCount += endRecordIndex - bytestream->currentRecordIndex();
306  }
307 #ifdef E57_MAX_VERBOSE
308  std::cout << " totalRecordCount=" << totalRecordCount << std::endl; //???
309 #endif
310 
312  if ( totalRecordCount == 0 )
313  {
314  break;
315  }
316 
325 
326 #ifdef E57_MAX_VERBOSE
327  std::cout << " currentPacketSize()=" << currentPacketSize() << std::endl; //???
328 #endif
329 
330 #ifdef E57_WRITE_CRAZY_PACKET_MODE
332  constexpr size_t E57_TARGET_PACKET_SIZE = 500;
333 #else
334  constexpr size_t E57_TARGET_PACKET_SIZE = ( DATA_PACKET_MAX * 3 / 4 );
335 #endif
337  if ( currentPacketSize() >= E57_TARGET_PACKET_SIZE )
338  { //???
339  packetWrite();
340  continue;
342  }
343 
347  float totalBitsPerRecord = 0; // an estimate of future performance
348  for ( auto &bytestream : bytestreams_ )
349  {
350  totalBitsPerRecord += bytestream->bitsPerRecord();
351  }
352 
353 #ifdef E57_MAX_VERBOSE
354  const float totalBytesPerRecord = std::max( totalBitsPerRecord / 8, 0.1F ); //??? trust
355 
356  std::cout << " totalBytesPerRecord=" << totalBytesPerRecord << std::endl; //???
357 #endif
358 
362 
365  for ( auto &bytestream : bytestreams_ )
366  {
367  if ( bytestream->currentRecordIndex() < endRecordIndex )
368  {
370  uint64_t recordCount = endRecordIndex - bytestream->currentRecordIndex();
371  recordCount = ( recordCount < 50ULL ) ? recordCount : 50ULL; // min(recordCount, 50ULL);
372  bytestream->processRecords( static_cast<unsigned>( recordCount ) );
373  }
374  }
375  }
376 
377  recordCount_ += requestedRecordCount;
378 
381  }
382 
383  size_t CompressedVectorWriterImpl::totalOutputAvailable() const
384  {
385  size_t total = 0;
386 
387  for ( const auto &bytestream : bytestreams_ )
388  {
389  total += bytestream->outputAvailable();
390  }
391 
392  return total;
393  }
394 
395  size_t CompressedVectorWriterImpl::currentPacketSize() const
396  {
398  return ( sizeof( DataPacketHeader ) + bytestreams_.size() * sizeof( uint16_t ) + totalOutputAvailable() );
399  }
400 
401  uint64_t CompressedVectorWriterImpl::packetWrite()
402  {
403 #ifdef E57_MAX_VERBOSE
404  std::cout << "CompressedVectorWriterImpl::packetWrite() called" << std::endl; //???
405 #endif
406 
408  size_t totalOutput = totalOutputAvailable();
409  if ( totalOutput == 0 )
410  {
411  return ( 0 );
412  }
413 #ifdef E57_MAX_VERBOSE
414  std::cout << " totalOutput=" << totalOutput << std::endl; //???
415 #endif
416 
418  size_t packetMaxPayloadBytes =
419  DATA_PACKET_MAX - sizeof( DataPacketHeader ) - bytestreams_.size() * sizeof( uint16_t );
420 #ifdef E57_MAX_VERBOSE
421  std::cout << " packetMaxPayloadBytes=" << packetMaxPayloadBytes << std::endl; //???
422 #endif
423 
426  std::vector<size_t> count( bytestreams_.size() );
427 
429  if ( totalOutput < packetMaxPayloadBytes )
430  {
432  for ( unsigned i = 0; i < bytestreams_.size(); i++ )
433  {
434  count.at( i ) = bytestreams_.at( i )->outputAvailable();
435  }
436  }
437  else
438  {
442  float fractionToSend = ( packetMaxPayloadBytes - 1 ) / static_cast<float>( totalOutput );
443  for ( unsigned i = 0; i < bytestreams_.size(); i++ )
444  {
446  count.at( i ) =
447  static_cast<unsigned>( std::floor( fractionToSend * bytestreams_.at( i )->outputAvailable() ) );
448  }
449  }
450 #ifdef E57_MAX_VERBOSE
451  for ( unsigned i = 0; i < bytestreams_.size(); i++ )
452  {
453  std::cout << " count[" << i << "]=" << count.at( i ) << std::endl; //???
454  }
455 #endif
456 
457 #ifdef E57_DEBUG
459  const size_t totalByteCount = std::accumulate( count.begin(), count.end(), 0 );
460 
461  if ( totalByteCount > packetMaxPayloadBytes )
462  {
463  throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "totalByteCount=" + toString( totalByteCount ) +
464  " packetMaxPayloadBytes=" + toString( packetMaxPayloadBytes ) );
465  }
466 #endif
467 
469  ImageFileImplSharedPtr imf( cVector_->destImageFile_ );
470 
473  char *packet = reinterpret_cast<char *>( &dataPacket_ );
474 #ifdef E57_MAX_VERBOSE
475  std::cout << " packet=" << packet << std::endl; //???
476 #endif
477 
479  dataPacket_.header.reset();
480 
483  auto bsbLength = reinterpret_cast<uint16_t *>( &packet[sizeof( DataPacketHeader )] );
484 #ifdef E57_MAX_VERBOSE
485  std::cout << " bsbLength=" << bsbLength << std::endl; //???
486 #endif
487  for ( unsigned i = 0; i < bytestreams_.size(); i++ )
488  {
489  bsbLength[i] = static_cast<uint16_t>( count.at( i ) ); // %%% Truncation
490 #ifdef E57_MAX_VERBOSE
491  std::cout << " Writing " << bsbLength[i] << " bytes into bytestream " << i << std::endl; //???
492 #endif
493  }
494 
496  char *p = reinterpret_cast<char *>( &bsbLength[bytestreams_.size()] );
497 #ifdef E57_MAX_VERBOSE
498  std::cout << " after bsbLength, p=" << p << std::endl; //???
499 #endif
500 
502  for ( size_t i = 0; i < bytestreams_.size(); i++ )
503  {
504  size_t n = count.at( i );
505 
506 #ifdef E57_DEBUG
509  if ( &p[n] > &packet[DATA_PACKET_MAX] )
510  {
511  throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "n=" + toString( n ) );
512  }
513 #endif
514 
516  bytestreams_.at( i )->outputRead( p, n );
517 
519  p += n;
520  }
521 
523  auto packetLength = static_cast<unsigned>( p - packet );
524 #ifdef E57_MAX_VERBOSE
525  std::cout << " packetLength=" << packetLength << std::endl; //???
526 #endif
527 
528 #ifdef E57_DEBUG
530  if ( packetLength != sizeof( DataPacketHeader ) + bytestreams_.size() * sizeof( uint16_t ) + totalByteCount )
531  {
532  throw E57_EXCEPTION2( E57_ERROR_INTERNAL, "packetLength=" + toString( packetLength ) + " bytestreamSize=" +
533  toString( bytestreams_.size() * sizeof( uint16_t ) ) +
534  " totalByteCount=" + toString( totalByteCount ) );
535  }
536 #endif
537 
539  while ( packetLength % 4 )
540  {
543  if ( p >= &packet[DATA_PACKET_MAX - 1] )
544  {
546  }
547  *p++ = 0;
548  packetLength++;
549 #ifdef E57_MAX_VERBOSE
550  std::cout << " padding with zero byte, new packetLength=" << packetLength << std::endl; //???
551 #endif
552  }
553 
555  dataPacket_.header.packetLogicalLengthMinus1 = static_cast<uint16_t>( packetLength - 1 ); // %%% Truncation
556  dataPacket_.header.bytestreamCount = static_cast<uint16_t>( bytestreams_.size() ); // %%% Truncation
557 
559  dataPacket_.verify( packetLength );
560 
562  uint64_t packetLogicalOffset = imf->allocateSpace( packetLength, false );
563  uint64_t packetPhysicalOffset = imf->file_->logicalToPhysical( packetLogicalOffset );
564  imf->file_->seek( packetLogicalOffset ); //??? have seekLogical and seekPhysical instead?
565  // more explicit
566  imf->file_->write( packet, packetLength );
567 
568 #ifdef E57_MAX_VERBOSE
569 // std::cout << "data packet:" << std::endl;
570 // dataPacket_.dump(4);
571 #endif
572 
579  if ( dataPacketsCount_ == 0 )
580  {
581  dataPhysicalOffset_ = packetPhysicalOffset;
582  }
583  dataPacketsCount_++;
584 
586 
588  return ( packetPhysicalOffset ); //??? needed
589  }
590 
591  void CompressedVectorWriterImpl::flush()
592  {
593  for ( auto &bytestream : bytestreams_ )
594  {
595  bytestream->registerFlushToOutput();
596  }
597  }
598 
599  void CompressedVectorWriterImpl::checkImageFileOpen( const char *srcFileName, int srcLineNumber,
600  const char *srcFunctionName ) const
601  {
602  // unimplemented...
603  }
604 
605  void CompressedVectorWriterImpl::checkWriterOpen( const char *srcFileName, int srcLineNumber,
606  const char *srcFunctionName ) const
607  {
608  if ( !isOpen_ )
609  {
610  throw E57Exception( E57_ERROR_WRITER_NOT_OPEN,
611  "imageFileName=" + cVector_->imageFileName() + " cvPathName=" + cVector_->pathName(),
612  srcFileName, srcLineNumber, srcFunctionName );
613  }
614  }
615 
616  void CompressedVectorWriterImpl::dump( int indent, std::ostream &os )
617  {
618  os << space( indent ) << "isOpen:" << isOpen_ << std::endl;
619 
620  for ( unsigned i = 0; i < sbufs_.size(); i++ )
621  {
622  os << space( indent ) << "sbufs[" << i << "]:" << std::endl;
623  sbufs_.at( i ).dump( indent + 4, os );
624  }
625 
626  os << space( indent ) << "cVector:" << std::endl;
627  cVector_->dump( indent + 4, os );
628 
629  os << space( indent ) << "proto:" << std::endl;
630  proto_->dump( indent + 4, os );
631 
632  for ( unsigned i = 0; i < bytestreams_.size(); i++ )
633  {
634  os << space( indent ) << "bytestreams[" << i << "]:" << std::endl;
635  bytestreams_.at( i )->dump( indent + 4, os );
636  }
637 
640  os << space( indent ) << "dataPacket:" << std::endl;
641  auto p = reinterpret_cast<uint8_t *>( &dataPacket_ );
642 
643  for ( unsigned i = 0; i < 40; ++i )
644  {
645  os << space( indent + 4 ) << "dataPacket[" << i << "]: " << static_cast<unsigned>( p[i] ) << std::endl;
646  }
647  os << space( indent + 4 ) << "more unprinted..." << std::endl;
648 
649  os << space( indent ) << "sectionHeaderLogicalStart: " << sectionHeaderLogicalStart_ << std::endl;
650  os << space( indent ) << "sectionLogicalLength: " << sectionLogicalLength_ << std::endl;
651  os << space( indent ) << "dataPhysicalOffset: " << dataPhysicalOffset_ << std::endl;
652  os << space( indent ) << "topIndexPhysicalOffset: " << topIndexPhysicalOffset_ << std::endl;
653  os << space( indent ) << "recordCount: " << recordCount_ << std::endl;
654  os << space( indent ) << "dataPacketsCount: " << dataPacketsCount_ << std::endl;
655  os << space( indent ) << "indexPacketsCount: " << indexPacketsCount_ << std::endl;
656  }
657 }
int count
#define E57_EXCEPTION2(ecode, context)
Definition: Common.h:68
#define E57_EXCEPTION1(ecode)
!! inline these rather than macros?
Definition: Common.h:66
void dump(int indent=0, std::ostream &os=std::cout)
std::shared_ptr< CompressedVectorNodeImpl > compressedVectorNode() const
void write(const size_t requestedRecordCount)
CompressedVectorWriterImpl(std::shared_ptr< CompressedVectorNodeImpl > ni, std::vector< SourceDestBuffer > &sbufs)
uint16_t bytestreamCount
Definition: Packet.h:119
uint16_t packetLogicalLengthMinus1
Definition: Packet.h:118
DataPacketHeader header
Definition: Packet.h:137
void verify(unsigned bufferLength=0) const
Definition: Packet.cpp:409
static std::shared_ptr< Encoder > EncoderFactory(unsigned bytestreamNumber, std::shared_ptr< CompressedVectorNodeImpl > cVector, std::vector< SourceDestBuffer > &sbuf, ustring &codecPath)
Definition: Encoder.cpp:42
int max(int a, int b)
Definition: cutil_math.h:48
QTextStream & endl(QTextStream &stream)
Definition: QtCompat.h:718
MiniVec< float, N > floor(const MiniVec< float, N > &a)
Definition: MiniVec.h:75
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_WRITER_NOT_OPEN
CompressedVectorWriter is no longer open.
Definition: E57Exception.h:86
std::string ustring
UTF-8 encodeded Unicode string.
Definition: E57Format.h:54
std::string toString(T x)
Definition: Common.h:80
constexpr int DATA_PACKET_MAX
maximum size of CompressedVector binary data packet
Definition: Packet.h:49
std::string space(size_t n)
Definition: Common.h:73
void verify(uint64_t filePhysicalSize=0)
void dump(int indent=0, std::ostream &os=std::cout) const
bool operator()(const std::shared_ptr< Encoder > &lhs, const std::shared_ptr< Encoder > &rhs) const