Skip to content

Commit

Permalink
{standard} A compressed vector with 0 records must still write a data…
Browse files Browse the repository at this point in the history
… packet

Part of #262
  • Loading branch information
asmaloney committed Oct 24, 2023
1 parent 8d9663e commit 8fa34d3
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 5 deletions.
51 changes: 51 additions & 0 deletions src/CompressedVectorWriterImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,12 @@ namespace e57
checkImageFileOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );
checkWriterOpen( __FILE__, __LINE__, static_cast<const char *>( __FUNCTION__ ) );

if ( requestedRecordCount == 0 )
{
packetWriteZeroRecords();
return;
}

// Check that requestedRecordCount is not larger than the sbufs
if ( requestedRecordCount > sbufs_.at( 0 ).impl()->capacity() )
{
Expand Down Expand Up @@ -610,6 +616,51 @@ namespace e57
return ( packetPhysicalOffset ); //??? needed
}

// If we don't have any records, write a packet which is only the header + zero padding.
// Code is a simplified version of packetWrite().
void CompressedVectorWriterImpl::packetWriteZeroRecords()
{
ImageFileImplSharedPtr imf( cVector_->destImageFile_ );

dataPacket_.header.reset();

// Use temp buf in object (is 64KBytes long) instead of allocating each time here
char *packet = reinterpret_cast<char *>( &dataPacket_ );

auto packetLength = sizeof( DataPacketHeader );

// packetLength must be multiple of 4, add zero padding
auto data = reinterpret_cast<char *>( &packet[sizeof( DataPacketHeader )] );
while ( packetLength % 4 )
{
*data++ = 0;

packetLength++;
}

// Prepare header in dataPacket_, now that we are sure of packetLength
dataPacket_.header.packetLogicalLengthMinus1 = static_cast<uint16_t>( packetLength - 1 );

// Double check that data packet is well formed
dataPacket_.verify( packetLength );

// Write packet at beginning of free space in file
uint64_t packetLogicalOffset = imf->allocateSpace( packetLength, false );
uint64_t packetPhysicalOffset = imf->file_->logicalToPhysical( packetLogicalOffset );

imf->file_->seek( packetLogicalOffset );
imf->file_->write( packet, packetLength );

// If first data packet written for this CompressedVector binary section,
// save address to put in section header
if ( dataPacketsCount_ == 0 )
{
dataPhysicalOffset_ = packetPhysicalOffset;
}

dataPacketsCount_++;
}

void CompressedVectorWriterImpl::flush()
{
for ( auto &bytestream : bytestreams_ )
Expand Down
2 changes: 2 additions & 0 deletions src/CompressedVectorWriterImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ namespace e57
size_t totalOutputAvailable() const;
size_t currentPacketSize() const;
uint64_t packetWrite();
void packetWriteZeroRecords();

void flush();

std::vector<SourceDestBuffer> sbufs_;
Expand Down
9 changes: 5 additions & 4 deletions src/Packet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,8 @@ void DataPacketHeader::reset()
void DataPacketHeader::verify( unsigned bufferLength ) const
{
// Verify that packet is correct type
// cppcheck-suppress knownConditionTrueFalse; (data is read as a blob, so the const might not
// be valid)
if ( packetType != DATA_PACKET )
{
throw E57_EXCEPTION2( ErrorBadCVPacket,
Expand Down Expand Up @@ -382,9 +384,8 @@ void DataPacketHeader::verify( unsigned bufferLength ) const
" bufferLength=" + toString( bufferLength ) );
}

// Make sure there is at least one entry in packet ??? 0 record cvect
// allowed?
if ( bytestreamCount == 0 )
// Make sure there is at least one entry in packet
if ( hasRecords() && ( bytestreamCount == 0 ) )
{
throw E57_EXCEPTION2( ErrorBadCVPacket,
"DATA; bytestreamCount=" + toString( bytestreamCount ) );
Expand Down Expand Up @@ -482,7 +483,7 @@ char *DataPacket::getBytestream( unsigned bytestreamNumber, unsigned &byteCount
{
throw E57_EXCEPTION2( ErrorInternal,
"bytestreamNumber=" + toString( bytestreamNumber ) +
"bytestreamCount=" + toString( header.bytestreamCount ) );
" bytestreamCount=" + toString( header.bytestreamCount ) );
}

// Calc positions in packet
Expand Down
10 changes: 9 additions & 1 deletion src/Packet.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,15 @@ namespace e57

void reset();

void verify( unsigned bufferLength = 0 ) const; //???use
void verify( unsigned bufferLength = 0 ) const;

// Does this packet have any records?
bool hasRecords() const
{
// If the packet does not have records, the logical length will be 8 bytes (the length of
// the header padded to 8-byte boundary).
return packetLogicalLengthMinus1 > 7;
}

#ifdef E57_ENABLE_DIAGNOSTIC_OUTPUT
void dump( int indent = 0, std::ostream &os = std::cout ) const;
Expand Down
28 changes: 28 additions & 0 deletions test/src/test_SimpleWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,34 @@ TEST( SimpleWriter, Empty )
E57_ASSERT_NO_THROW( e57::Writer writer( "./empty.e57", options ) );
}

TEST( SimpleWriter, ZeroPoints )
{
e57::WriterOptions options;
options.guid = "Zero Points GUID";

e57::Writer *writer = nullptr;

E57_ASSERT_NO_THROW( writer = new e57::Writer( "./ZeroPoints.e57", options ) );

constexpr uint16_t cNumPoints = 0;

e57::Data3D header;
header.guid = "Zero Points Header GUID";
header.pointCount = cNumPoints;

// For a valid file, we need to specify cartesian or spherical.
header.pointFields.cartesianXField = true;
header.pointFields.cartesianYField = true;
header.pointFields.cartesianZField = true;
header.cartesianBounds.xMinimum = 0.0;

e57::Data3DPointsDouble pointsData( header );

E57_ASSERT_NO_THROW( writer->WriteData3DData( header, pointsData ) );

delete writer;
}

TEST( SimpleWriter, InvalidData3DValueCartesian )
{
e57::WriterOptions options;
Expand Down

0 comments on commit 8fa34d3

Please sign in to comment.