1 /*
2 * Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
3 *
4 * Permission is hereby granted, free of charge, to any person or organization
5 * obtaining a copy of the software and accompanying documentation covered by
6 * this license (the "Software") to use, reproduce, display, distribute,
7 * execute, and transmit the Software, and to prepare derivative works of the
8 * Software, and to permit third-parties to whom the Software is furnished to
9 * do so, all subject to the following:
10 *
11 * The copyright notices in the Software and this entire statement, including
12 * the above license grant, this restriction and the following disclaimer,
13 * must be included in all copies of the Software, in whole or in part, and
14 * all derivative works of the Software, unless such copies or derivative
15 * works are solely in the form of machine-executable object code generated by
16 * a source language processor.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
21 * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
22 * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
23 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
25 */
26
27 #include <cstring>
28
29 #include "CheckedFile.h"
30 #include "Packet.h"
31
32
33 using namespace e57;
34
35 struct IndexPacket
36 {
37 static constexpr unsigned MAX_ENTRIES = 2048;
38
39 const uint8_t packetType = INDEX_PACKET;
40
41 uint8_t packetFlags = 0; // flag bitfields
42 uint16_t packetLogicalLengthMinus1 = 0;
43 uint16_t entryCount = 0;
44 uint8_t indexLevel = 0;
45 uint8_t reserved1[9] = {}; // must be zero
46
47 struct IndexPacketEntry
48 {
49 uint64_t chunkRecordNumber = 0;
50 uint64_t chunkPhysicalOffset = 0;
51 } entries[MAX_ENTRIES];
52
53 void verify(unsigned bufferLength = 0, uint64_t totalRecordCount = 0, uint64_t fileSize = 0) const;
54
55 #ifdef E57_DEBUG
56 void dump(int indent = 0, std::ostream& os = std::cout) const;
57 #endif
58 };
59
60 struct EmptyPacketHeader
61 {
62 const uint8_t packetType = EMPTY_PACKET;
63
64 uint8_t reserved1 = 0; // must be zero
65 uint16_t packetLogicalLengthMinus1 = 0;
66
67 void verify(unsigned bufferLength = 0) const; //???use
68
69 #ifdef E57_DEBUG
70 void dump(int indent = 0, std::ostream& os = std::cout) const;
71 #endif
72 };
73
74 //=============================================================================
75 // PacketReadCache
76
PacketReadCache(CheckedFile * cFile,unsigned packetCount)77 PacketReadCache::PacketReadCache(CheckedFile* cFile, unsigned packetCount)
78 : cFile_(cFile),
79 entries_(packetCount)
80 {
81 if (packetCount == 0)
82 {
83 throw E57_EXCEPTION2(E57_ERROR_INTERNAL, "packetCount=" + toString(packetCount));
84 }
85 }
86
lock(uint64_t packetLogicalOffset,char * & pkt)87 std::unique_ptr<PacketLock> PacketReadCache::lock( uint64_t packetLogicalOffset, char* &pkt )
88 {
89 #ifdef E57_MAX_VERBOSE
90 std::cout << "PacketReadCache::lock() called, packetLogicalOffset=" << packetLogicalOffset << std::endl;
91 #endif
92
93 /// Only allow one locked packet at a time.
94 if ( lockCount_ > 0 )
95 {
96 throw E57_EXCEPTION2(E57_ERROR_INTERNAL, "lockCount=" + toString(lockCount_));
97 }
98
99 /// Offset can't be 0
100 if ( packetLogicalOffset == 0 )
101 {
102 throw E57_EXCEPTION2(E57_ERROR_INTERNAL, "packetLogicalOffset=" + toString(packetLogicalOffset));
103 }
104
105 /// Linear scan for matching packet offset in cache
106 for ( unsigned i = 0; i < entries_.size(); ++i )
107 {
108 auto &entry = entries_[i];
109
110 if (packetLogicalOffset == entry.logicalOffset_)
111 {
112 /// Found a match, so don't have to read anything
113 #ifdef E57_MAX_VERBOSE
114 std::cout << " Found matching cache entry, index=" << i << std::endl;
115 #endif
116 /// Mark entry with current useCount (keeps track of age of entry).
117 entry.lastUsed_ = ++useCount_;
118
119 /// Publish buffer address to caller
120 pkt = entry.buffer_;
121
122 /// Create lock so we are sure that we will be unlocked when use is finished.
123 std::unique_ptr<PacketLock> plock( new PacketLock( this, i ) );
124
125 /// Increment cache lock just before return
126 ++lockCount_;
127
128 return plock;
129 }
130 }
131 /// Get here if didn't find a match already in cache.
132
133 /// Find least recently used (LRU) packet buffer
134 unsigned oldestEntry = 0;
135 unsigned oldestUsed = entries_.at(0).lastUsed_;
136
137 for ( unsigned i = 0; i < entries_.size(); ++i )
138 {
139 const auto &entry = entries_[i];
140
141 if ( entry.lastUsed_ < oldestUsed )
142 {
143 oldestEntry = i;
144 oldestUsed = entry.lastUsed_;
145 }
146 }
147 #ifdef E57_MAX_VERBOSE
148 std::cout << " Oldest entry=" << oldestEntry << " lastUsed=" << oldestUsed << std::endl;
149 #endif
150
151 readPacket(oldestEntry, packetLogicalOffset);
152
153 /// Publish buffer address to caller
154 pkt = entries_[oldestEntry].buffer_;
155
156 /// Create lock so we are sure we will be unlocked when use is finished.
157 std::unique_ptr<PacketLock> plock( new PacketLock( this, oldestEntry ) );
158
159 /// Increment cache lock just before return
160 ++lockCount_;
161
162 return plock;
163 }
164
unlock(unsigned lockedEntry)165 void PacketReadCache::unlock(unsigned lockedEntry)
166 {
167 //??? why lockedEntry not used?
168 #ifdef E57_MAX_VERBOSE
169 std::cout << "PacketReadCache::unlock() called, lockedEntry=" << lockedEntry << std::endl;
170 #endif
171
172 if (lockCount_ != 1)
173 {
174 throw E57_EXCEPTION2(E57_ERROR_INTERNAL, "lockCount=" + toString(lockCount_));
175 }
176
177 --lockCount_;
178 }
179
readPacket(unsigned oldestEntry,uint64_t packetLogicalOffset)180 void PacketReadCache::readPacket(unsigned oldestEntry, uint64_t packetLogicalOffset)
181 {
182 #ifdef E57_MAX_VERBOSE
183 std::cout << "PacketReadCache::readPacket() called, oldestEntry=" << oldestEntry << " packetLogicalOffset=" << packetLogicalOffset << std::endl;
184 #endif
185
186 /// Read header of packet first to get length. Use EmptyPacketHeader since it has the commom fields to all packets.
187 EmptyPacketHeader header;
188
189 cFile_->seek(packetLogicalOffset, CheckedFile::Logical);
190 cFile_->read(reinterpret_cast<char*>(&header), sizeof(header));
191
192 /// Can't verify packet header here, because it is not really an EmptyPacketHeader.
193 unsigned packetLength = header.packetLogicalLengthMinus1+1;
194
195 /// Be paranoid about packetLength before read
196 if (packetLength > DATA_PACKET_MAX)
197 {
198 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET, "packetLength=" + toString(packetLength));
199 }
200
201 auto &entry = entries_.at(oldestEntry);
202
203 /// Now read in whole packet into preallocated buffer_. Note buffer is
204 cFile_->seek(packetLogicalOffset, CheckedFile::Logical);
205 cFile_->read(entry.buffer_, packetLength);
206
207 /// Verify that packet is good.
208 switch (header.packetType)
209 {
210 case DATA_PACKET: {
211 auto dpkt = reinterpret_cast<DataPacket*>(entry.buffer_);
212
213 dpkt->verify(packetLength);
214 #ifdef E57_MAX_VERBOSE
215 std::cout << " data packet:" << std::endl;
216 dpkt->dump(4); //???
217 #endif
218 }
219 break;
220 case INDEX_PACKET: {
221 auto ipkt = reinterpret_cast<IndexPacket*>(entry.buffer_);
222
223 ipkt->verify(packetLength);
224 #ifdef E57_MAX_VERBOSE
225 std::cout << " index packet:" << std::endl;
226 ipkt->dump(4); //???
227 #endif
228 }
229 break;
230 case EMPTY_PACKET: {
231 auto hp = reinterpret_cast<EmptyPacketHeader*>(entry.buffer_);
232
233 hp->verify(packetLength);
234 #ifdef E57_MAX_VERBOSE
235 std::cout << " empty packet:" << std::endl;
236 hp->dump(4); //???
237 #endif
238 }
239 break;
240 default:
241 throw E57_EXCEPTION2(E57_ERROR_INTERNAL, "packetType=" + toString(header.packetType));
242 }
243
244 entry.logicalOffset_ = packetLogicalOffset;
245
246 /// Mark entry with current useCount (keeps track of age of entry).
247 /// This is a cache, so a small hiccup when useCount_ overflows won't hurt.
248 entry.lastUsed_ = ++useCount_;
249 }
250
251 #ifdef E57_DEBUG
dump(int indent,std::ostream & os)252 void PacketReadCache::dump(int indent, std::ostream& os)
253 {
254 os << space(indent) << "lockCount: " << lockCount_ << std::endl;
255 os << space(indent) << "useCount: " << useCount_ << std::endl;
256 os << space(indent) << "entries:" << std::endl;
257 for (unsigned i=0; i < entries_.size(); i++) {
258 os << space(indent) << "entry[" << i << "]:" << std::endl;
259 os << space(indent+4) << "logicalOffset: " << entries_[i].logicalOffset_ << std::endl;
260 os << space(indent+4) << "lastUsed: " << entries_[i].lastUsed_ << std::endl;
261 if (entries_[i].logicalOffset_ != 0) {
262 os << space(indent+4) << "packet:" << std::endl;
263 switch (reinterpret_cast<EmptyPacketHeader*>(entries_.at(i).buffer_)->packetType) {
264 case DATA_PACKET: {
265 auto dpkt = reinterpret_cast<DataPacket*>(entries_.at(i).buffer_);
266 dpkt->dump(indent+6, os);
267 }
268 break;
269 case INDEX_PACKET: {
270 auto ipkt = reinterpret_cast<IndexPacket*>(entries_.at(i).buffer_);
271 ipkt->dump(indent+6, os);
272 }
273 break;
274 case EMPTY_PACKET: {
275 auto hp = reinterpret_cast<EmptyPacketHeader*>(entries_.at(i).buffer_);
276 hp->dump(indent+6, os);
277 }
278 break;
279 default:
280 throw E57_EXCEPTION2(E57_ERROR_INTERNAL,
281 "packetType=" + toString(reinterpret_cast<EmptyPacketHeader*>(entries_.at(i).buffer_)->packetType));
282 }
283 }
284 }
285 }
286 #endif
287
288 //=============================================================================
289 // PacketLock
290
PacketLock(PacketReadCache * cache,unsigned cacheIndex)291 PacketLock::PacketLock(PacketReadCache* cache, unsigned cacheIndex)
292 : cache_(cache),
293 cacheIndex_(cacheIndex)
294 {
295 #ifdef E57_MAX_VERBOSE
296 std::cout << "PacketLock() called" << std::endl;
297 #endif
298 }
299
~PacketLock()300 PacketLock::~PacketLock()
301 {
302 #ifdef E57_MAX_VERBOSE
303 std::cout << "~PacketLock() called" << std::endl;
304 #endif
305 try {
306 /// Note cache must live longer than lock, this is reasonable assumption.
307 cache_->unlock(cacheIndex_);
308 } catch (...) {
309 //??? report?
310 }
311 }
312
313 //=============================================================================
314 // DataPacketHeader
315
DataPacketHeader()316 DataPacketHeader::DataPacketHeader()
317 {
318 /// Double check that packet struct is correct length. Watch out for RTTI increasing the size.
319 static_assert( sizeof( DataPacketHeader ) == 6, "Unexpected size of DataPacketHeader" );
320 }
321
reset()322 void DataPacketHeader::reset()
323 {
324 packetFlags = 0;
325 packetLogicalLengthMinus1 = 0;
326 bytestreamCount = 0;
327 }
328
verify(unsigned bufferLength) const329 void DataPacketHeader::verify(unsigned bufferLength) const
330 {
331 /// Verify that packet is correct type
332 if (packetType != DATA_PACKET)
333 {
334 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET, "packetType=" + toString(packetType));
335 }
336
337 /// ??? check reserved flags zero?
338
339 /// Check packetLength is at least large enough to hold header
340 unsigned packetLength = packetLogicalLengthMinus1+1;
341 if (packetLength < sizeof(*this))
342 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET, "packetLength=" + toString(packetLength));
343
344 /// Check packet length is multiple of 4
345 if (packetLength % 4)
346 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET, "packetLength=" + toString(packetLength));
347
348 /// Check actual packet length is large enough.
349 if (bufferLength > 0 && packetLength > bufferLength) {
350 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET,
351 "packetLength=" + toString(packetLength)
352 + " bufferLength=" + toString(bufferLength));
353 }
354
355 /// Make sure there is at least one entry in packet ??? 0 record cvect allowed?
356 if (bytestreamCount == 0)
357 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET, "bytestreamCount=" + toString(bytestreamCount));
358
359 /// Check packet is at least long enough to hold bytestreamBufferLength array
360 if (sizeof(DataPacketHeader) + 2*bytestreamCount > packetLength) {
361 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET,
362 "packetLength=" + toString(packetLength)
363 + " bytestreamCount=" + toString(bytestreamCount));
364 }
365 }
366
367 #ifdef E57_DEBUG
dump(int indent,std::ostream & os) const368 void DataPacketHeader::dump(int indent, std::ostream& os) const
369 {
370 os << space(indent) << "packetType: " << static_cast<unsigned>(packetType) << std::endl;
371 os << space(indent) << "packetFlags: " << static_cast<unsigned>(packetFlags) << std::endl;
372 os << space(indent) << "packetLogicalLengthMinus1: " << packetLogicalLengthMinus1 << std::endl;
373 os << space(indent) << "bytestreamCount: " << bytestreamCount << std::endl;
374 }
375 #endif
376
377 //=============================================================================
378 // DataPacket
379
DataPacket()380 DataPacket::DataPacket()
381 {
382 /// Double check that packet struct is correct length. Watch out for RTTI increasing the size.
383 static_assert( sizeof( DataPacket ) == 64*1024, "Unexpected size of DataPacket" );
384 }
385
verify(unsigned bufferLength) const386 void DataPacket::verify(unsigned bufferLength) const
387 {
388 //??? do all packets need versions? how extend without breaking older checking? need to check file version#?
389
390 /// Verify header is good
391 auto hp = reinterpret_cast<const DataPacketHeader*>(this);
392
393 hp->verify(bufferLength);
394
395 /// Calc sum of lengths of each bytestream buffer in this packet
396 auto bsbLength = reinterpret_cast<const uint16_t*>(&payload[0]);
397 unsigned totalStreamByteCount = 0;
398
399 for (unsigned i=0; i < header.bytestreamCount; i++)
400 {
401 totalStreamByteCount += bsbLength[i];
402 }
403
404 /// Calc size of packet needed
405 const unsigned packetLength = header.packetLogicalLengthMinus1+1;
406 const unsigned needed = sizeof(DataPacketHeader) + 2*header.bytestreamCount + totalStreamByteCount;
407 #ifdef E57_MAX_VERBOSE
408 std::cout << "needed=" << needed << " actual=" << packetLength << std::endl; //???
409 #endif
410
411 /// If needed is not with 3 bytes of actual packet size, have an error
412 if (needed > packetLength || needed+3 < packetLength)
413 {
414 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET,
415 "needed=" + toString(needed)
416 + "packetLength=" + toString(packetLength));
417 }
418
419 /// Verify that padding at end of packet is zero
420 for (unsigned i=needed; i < packetLength; i++)
421 {
422 if (reinterpret_cast<const char*>(this)[i] != 0)
423 {
424 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET, "i=" + toString(i));
425 }
426 }
427 }
428
getBytestream(unsigned bytestreamNumber,unsigned & byteCount)429 char* DataPacket::getBytestream(unsigned bytestreamNumber, unsigned& byteCount)
430 {
431 #ifdef E57_MAX_VERBOSE
432 std::cout << "getBytestream called, bytestreamNumber=" << bytestreamNumber << std::endl;
433 #endif
434
435 /// Verify that packet is correct type
436 if (header.packetType != DATA_PACKET)
437 {
438 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET, "packetType=" + toString(header.packetType));
439 }
440
441 /// Check bytestreamNumber in bounds
442 if (bytestreamNumber >= header.bytestreamCount)
443 {
444 throw E57_EXCEPTION2(E57_ERROR_INTERNAL,
445 "bytestreamNumber=" + toString(bytestreamNumber)
446 + "bytestreamCount=" + toString(header.bytestreamCount));
447 }
448
449 /// Calc positions in packet
450 auto bsbLength = reinterpret_cast<uint16_t*>(&payload[0]);
451 auto streamBase = reinterpret_cast<char*>(&bsbLength[header.bytestreamCount]);
452
453 /// Sum size of preceeding stream buffers to get position
454 unsigned totalPreceeding = 0;
455 for (unsigned i=0; i < bytestreamNumber; i++)
456 totalPreceeding += bsbLength[i];
457
458 byteCount = bsbLength[bytestreamNumber];
459
460 /// Double check buffer is completely within packet
461 if (sizeof(DataPacketHeader) + 2*header.bytestreamCount + totalPreceeding + byteCount > header.packetLogicalLengthMinus1 + 1U)
462 {
463 throw E57_EXCEPTION2(E57_ERROR_INTERNAL,
464 "bytestreamCount=" + toString(header.bytestreamCount)
465 + " totalPreceeding=" + toString(totalPreceeding)
466 + " byteCount=" + toString(byteCount)
467 + " packetLogicalLengthMinus1=" + toString(header.packetLogicalLengthMinus1));
468 }
469
470 /// Return start of buffer
471 return(&streamBase[totalPreceeding]);
472 }
473
getBytestreamBufferLength(unsigned bytestreamNumber)474 unsigned DataPacket::getBytestreamBufferLength(unsigned bytestreamNumber)
475 {
476 //??? for now:
477 unsigned byteCount;
478 (void) getBytestream(bytestreamNumber, byteCount);
479 return(byteCount);
480 }
481
482 #ifdef E57_DEBUG
dump(int indent,std::ostream & os) const483 void DataPacket::dump(int indent, std::ostream& os) const
484 {
485 if (header.packetType != DATA_PACKET)
486 {
487 throw E57_EXCEPTION2(E57_ERROR_INTERNAL, "packetType=" + toString(header.packetType));
488 }
489
490 reinterpret_cast<const DataPacketHeader*>(this)->dump(indent, os);
491
492 auto bsbLength = reinterpret_cast<const uint16_t*>(&payload[0]);
493 auto p = reinterpret_cast<const uint8_t*>(&bsbLength[header.bytestreamCount]);
494
495 for (unsigned i=0; i < header.bytestreamCount; i++)
496 {
497 os << space(indent) << "bytestream[" << i << "]:" << std::endl;
498 os << space(indent+4) << "length: " << bsbLength[i] << std::endl;
499 /*====
500 unsigned j;
501 for (j=0; j < bsbLength[i] && j < 10; j++)
502 os << space(indent+4) << "byte[" << j << "]=" << (unsigned)p[j] << endl;
503 if (j < bsbLength[i])
504 os << space(indent+4) << bsbLength[i]-j << " more unprinted..." << endl;
505 ====*/
506 p += bsbLength[i];
507 if (p - reinterpret_cast<const uint8_t*>(this) > DATA_PACKET_MAX)
508 {
509 throw E57_EXCEPTION2(E57_ERROR_INTERNAL, "size=" + toString(p - reinterpret_cast<const uint8_t*>(this)));
510 }
511 }
512 }
513 #endif
514
515 //=============================================================================
516 // IndexPacket
517
verify(unsigned bufferLength,uint64_t totalRecordCount,uint64_t fileSize) const518 void IndexPacket::verify(unsigned bufferLength, uint64_t totalRecordCount, uint64_t fileSize) const
519 {
520 //??? do all packets need versions? how extend without breaking older checking? need to check file version#?
521
522 /// Verify that packet is correct type
523 if (packetType != INDEX_PACKET)
524 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET, "packetType=" + toString(packetType));
525
526 /// Check packetLength is at least large enough to hold header
527 unsigned packetLength = packetLogicalLengthMinus1+1;
528 if (packetLength < sizeof(*this))
529 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET, "packetLength=" + toString(packetLength));
530
531 /// Check packet length is multiple of 4
532 if (packetLength % 4)
533 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET, "packetLength=" + toString(packetLength));
534
535 /// Make sure there is at least one entry in packet ??? 0 record cvect allowed?
536 if (entryCount == 0)
537 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET, "entryCount=" + toString(entryCount));
538
539 /// Have to have <= 2048 entries
540 if (entryCount > MAX_ENTRIES)
541 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET, "entryCount=" + toString(entryCount));
542
543 /// Index level should be <= 5. Because (5+1)* 11 bits = 66 bits, which will cover largest number of chunks possible.
544 if (indexLevel > 5)
545 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET, "indexLevel=" + toString(indexLevel));
546
547 /// Index packets above level 0 must have at least two entries (otherwise no point to existing).
548 ///??? check that this is in spec
549 if (indexLevel > 0 && entryCount < 2)
550 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET, "indexLevel=" + toString(indexLevel) + " entryCount=" + toString(entryCount));
551
552 /// If not later version, verify reserved fields are zero. ??? test file version
553 /// if (version <= E57_FORMAT_MAJOR) { //???
554 for (unsigned i=0; i < sizeof(reserved1); i++) {
555 if (reserved1[i] != 0)
556 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET, "i=" + toString(i));
557 }
558
559 /// Check actual packet length is large enough.
560 if (bufferLength > 0 && packetLength > bufferLength) {
561 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET,
562 "packetLength=" + toString(packetLength)
563 + " bufferLength=" + toString(bufferLength));
564 }
565
566 /// Check if entries will fit in space provided
567 unsigned neededLength = 16 + 8*entryCount;
568 if (packetLength < neededLength) {
569 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET,
570 "packetLength=" + toString(packetLength)
571 + " neededLength=" + toString(neededLength));
572 }
573
574 #ifdef E57_MAX_DEBUG
575 /// Verify padding at end is zero.
576 const char* p = reinterpret_cast<const char*>(this);
577 for (unsigned i=neededLength; i < packetLength; i++) {
578 if (p[i] != 0)
579 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET, "i=" + toString(i));
580 }
581
582 /// Verify records and offsets are in sorted order
583 for (unsigned i=0; i < entryCount; i++) {
584 /// Check chunkRecordNumber is in bounds
585 if (totalRecordCount > 0 && entries[i].chunkRecordNumber >= totalRecordCount) {
586 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET,
587 "i=" + toString(i)
588 + " chunkRecordNumber=" + toString(entries[i].chunkRecordNumber)
589 + " totalRecordCount=" + toString(totalRecordCount));
590 }
591
592 /// Check record numbers are strictly increasing
593 if (i > 0 && entries[i-1].chunkRecordNumber >= entries[i].chunkRecordNumber) {
594 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET,
595 "i=" + toString(i)
596 + " prevChunkRecordNumber=" + toString(entries[i-1].chunkRecordNumber)
597 + " currentChunkRecordNumber=" + toString(entries[i].chunkRecordNumber));
598 }
599
600 /// Check chunkPhysicalOffset is in bounds
601 if (fileSize > 0 && entries[i].chunkPhysicalOffset >= fileSize) {
602 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET,
603 "i=" + toString(i)
604 + " chunkPhysicalOffset=" + toString(entries[i].chunkPhysicalOffset)
605 + " fileSize=" + toString(fileSize));
606 }
607
608 /// Check chunk offsets are strictly increasing
609 if (i > 0 && entries[i-1].chunkPhysicalOffset >= entries[i].chunkPhysicalOffset) {
610 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET,
611 "i=" + toString(i)
612 + " prevChunkPhysicalOffset=" + toString(entries[i-1].chunkPhysicalOffset)
613 + " currentChunkPhysicalOffset=" + toString(entries[i].chunkPhysicalOffset));
614 }
615 }
616 #endif
617 }
618
619 #ifdef E57_DEBUG
dump(int indent,std::ostream & os) const620 void IndexPacket::dump(int indent, std::ostream& os) const
621 {
622 os << space(indent) << "packetType: " << static_cast<unsigned>(packetType) << std::endl;
623 os << space(indent) << "packetFlags: " << static_cast<unsigned>(packetFlags) << std::endl;
624 os << space(indent) << "packetLogicalLengthMinus1: " << packetLogicalLengthMinus1 << std::endl;
625 os << space(indent) << "entryCount: " << entryCount << std::endl;
626 os << space(indent) << "indexLevel: " << indexLevel << std::endl;
627 unsigned i;
628 for (i=0; i < entryCount && i < 10; i++) {
629 os << space(indent) << "entry[" << i << "]:" << std::endl;
630 os << space(indent+4) << "chunkRecordNumber: " << entries[i].chunkRecordNumber << std::endl;
631 os << space(indent+4) << "chunkPhysicalOffset: " << entries[i].chunkPhysicalOffset << std::endl;
632 }
633 if (i < entryCount)
634 {
635 os << space(indent) << entryCount-i << "more entries unprinted..." << std::endl;
636 }
637 }
638 #endif
639
640 //=============================================================================
641 // EmptyPacketHeader
642
verify(unsigned bufferLength) const643 void EmptyPacketHeader::verify(unsigned bufferLength) const
644 {
645 /// Verify that packet is correct type
646 if (packetType != EMPTY_PACKET)
647 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET, "packetType=" + toString(packetType));
648
649 /// Check packetLength is at least large enough to hold header
650 unsigned packetLength = packetLogicalLengthMinus1+1;
651 if (packetLength < sizeof(*this))
652 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET, "packetLength=" + toString(packetLength));
653
654 /// Check packet length is multiple of 4
655 if (packetLength % 4)
656 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET, "packetLength=" + toString(packetLength));
657
658 /// Check actual packet length is large enough.
659 if (bufferLength > 0 && packetLength > bufferLength) {
660 throw E57_EXCEPTION2(E57_ERROR_BAD_CV_PACKET,
661 "packetLength=" + toString(packetLength)
662 + " bufferLength=" + toString(bufferLength));
663 }
664 }
665
666 #ifdef E57_DEBUG
dump(int indent,std::ostream & os) const667 void EmptyPacketHeader::dump(int indent, std::ostream& os) const
668 {
669 os << space(indent) << "packetType: " << static_cast<unsigned>(packetType) << std::endl;
670 os << space(indent) << "packetLogicalLengthMinus1: " << packetLogicalLengthMinus1 << std::endl;
671 }
672 #endif
673