1 /****************************************************************************** 2 * Copyright (c) 2014, Hobu Inc., hobu@hobu.co 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following 8 * conditions are met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided 15 * with the distribution. 16 * * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the 17 * names of its contributors may be used to endorse or promote 18 * products derived from this software without specific prior 19 * written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 28 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 32 * OF SUCH DAMAGE. 33 ****************************************************************************/ 34 35 #pragma once 36 37 #include <vector> 38 39 #include "pdal_util_export.hpp" 40 #include "portable_endian.hpp" 41 42 namespace pdal 43 { 44 45 /** 46 Buffer wrapper for input of binary data from a buffer. 47 */ 48 class PDAL_DLL Extractor 49 { 50 public: 51 /** 52 Construct an extractor to operate on a buffer. 53 54 \param buf Buffer to extract from. 55 \param size Buffer size. 56 */ Extractor(const char * buf,std::size_t size)57 Extractor(const char *buf, std::size_t size) : m_eback(buf), 58 m_egptr(buf + size), m_gptr(buf) 59 {} 60 61 public: 62 /** 63 Determine if the buffer is good. 64 65 \return Whether the buffer is good. 66 */ operator bool()67 operator bool () 68 { return good(); } 69 70 /** 71 Seek to a position in the buffer. 72 73 \param pos Position to seek in buffer. 74 */ seek(std::size_t pos)75 void seek(std::size_t pos) 76 { m_gptr = m_eback + pos; } 77 78 /** 79 Advance buffer position. 80 81 \param cnt Number of bytes to skip in buffer. 82 */ skip(std::size_t cnt)83 void skip(std::size_t cnt) 84 { m_gptr += cnt; } 85 86 /** 87 Return the get position of buffer. 88 89 \return Get position. 90 */ position() const91 size_t position() const 92 { return m_gptr - m_eback; } 93 94 /** 95 Determine whether the extractor is good (the get pointer is in the 96 buffer). 97 98 \return Whether the get pointer is valid. 99 */ good() const100 bool good() const 101 { return m_gptr < m_egptr; } 102 103 /** 104 Extract a string of a particular size from the buffer. Trim trailing 105 null bytes. 106 107 \param s String to extract to. 108 \param size Number of bytes to extract from buffer into string. 109 */ get(std::string & s,size_t size)110 void get(std::string& s, size_t size) 111 { 112 s = std::string(m_gptr, size); 113 m_gptr += size; 114 while (--size) 115 { 116 if (s[size] != '\0') 117 break; 118 else if (size == 0) 119 { 120 s.clear(); 121 return; 122 } 123 } 124 s.resize(size + 1); 125 } 126 127 /** 128 Extract data to char vector. Vector must be sized to indicate 129 number of bytes to extract. 130 131 \param buf Vector to which bytes should be extracted. 132 */ get(std::vector<char> & buf)133 void get(std::vector<char>& buf) 134 { 135 memcpy((char *)buf.data(), m_gptr, buf.size()); 136 m_gptr += buf.size(); 137 } 138 139 /** 140 Extract data to unsigned char vector. Vector must be sized to 141 indicate number of bytes to extract. 142 143 \param buf Vector to which bytes should be extracted. 144 */ get(std::vector<unsigned char> & buf)145 void get(std::vector<unsigned char>& buf) 146 { 147 memcpy((char *)buf.data(), m_gptr, buf.size()); 148 m_gptr += buf.size(); 149 } 150 151 /** 152 Extract data into a provided buffer. 153 154 \param buf Pointer to buffer to which bytes should be extracted. 155 \param size Number of bytes to extract. 156 */ get(char * buf,size_t size)157 void get(char *buf, size_t size) 158 { 159 memcpy(buf, m_gptr, size); 160 m_gptr += size; 161 } 162 163 /** 164 Extract data into a provided unsigned buffer. 165 166 \param buf Pointer to buffer to which bytes should be extracted. 167 \param size Number of bytes to extract. 168 */ get(unsigned char * buf,size_t size)169 void get(unsigned char *buf, size_t size) 170 { 171 memcpy(buf, m_gptr, size); 172 m_gptr += size; 173 } 174 175 virtual Extractor& operator >> (uint8_t& v) = 0; 176 virtual Extractor& operator >> (int8_t& v) = 0; 177 virtual Extractor& operator >> (uint16_t& v) = 0; 178 virtual Extractor& operator >> (int16_t& v) = 0; 179 virtual Extractor& operator >> (uint32_t& v) = 0; 180 virtual Extractor& operator >> (int32_t& v) = 0; 181 virtual Extractor& operator >> (uint64_t& v) = 0; 182 virtual Extractor& operator >> (int64_t& v) = 0; 183 virtual Extractor& operator >> (float& v) = 0; 184 virtual Extractor& operator >> (double& v) = 0; 185 186 protected: 187 const char *m_eback; ///< Start of the buffer (name from std::streambuf) 188 const char *m_egptr; ///< End of the buffer. 189 const char *m_gptr; ///< Current get position. 190 }; 191 192 /** 193 Wrapper extraction of little-endian data from a buffer to host ordering. 194 */ 195 class PDAL_DLL LeExtractor : public Extractor 196 { 197 public: 198 /** 199 Construct extractor for a buffer. 200 201 \param buf Buffer from which to extract. 202 \param size Size of buffer. 203 */ LeExtractor(const char * buf,std::size_t size)204 LeExtractor(const char *buf, std::size_t size) : Extractor(buf, size) 205 {} 206 207 /** 208 Extract an unsigned byte from a buffer. 209 210 \param v Unsigned byte to extract to. 211 \return This extractor. 212 */ operator >>(uint8_t & v)213 LeExtractor& operator >> (uint8_t& v) 214 { 215 v = *(const uint8_t *)m_gptr++; 216 return *this; 217 } 218 219 /** 220 Extract a byte from a buffer. 221 222 \param v Byte to extract to. 223 \return This extractor. 224 */ operator >>(int8_t & v)225 LeExtractor& operator >> (int8_t& v) 226 { 227 v = *(const int8_t *)m_gptr++; 228 return *this; 229 } 230 231 /** 232 Extract an unsgined short from a buffer. 233 234 \param v Short to extract to. 235 \return This extractor. 236 */ operator >>(uint16_t & v)237 LeExtractor& operator >> (uint16_t& v) 238 { 239 memcpy(&v, m_gptr, sizeof(v)); 240 v = le16toh(v); 241 m_gptr += sizeof(v); 242 return *this; 243 } 244 245 /** 246 Extract a short from a buffer. 247 248 \param v Short to extract to. 249 \return This extractor. 250 */ operator >>(int16_t & v)251 LeExtractor& operator >> (int16_t& v) 252 { 253 memcpy(&v, m_gptr, sizeof(v)); 254 v = (int16_t)le16toh((uint16_t)v); 255 m_gptr += sizeof(v); 256 return *this; 257 } 258 259 /** 260 Extract an unsigned int from a buffer. 261 262 \param v Unsigned int to extract to. 263 \return This extractor. 264 */ operator >>(uint32_t & v)265 LeExtractor& operator >> (uint32_t& v) 266 { 267 memcpy(&v, m_gptr, sizeof(v)); 268 v = le32toh(v); 269 m_gptr += sizeof(v); 270 return *this; 271 } 272 273 /** 274 Extract an int from a buffer. 275 276 \param v int to extract to. 277 \return This extractor. 278 */ operator >>(int32_t & v)279 LeExtractor& operator >> (int32_t& v) 280 { 281 memcpy(&v, m_gptr, sizeof(v)); 282 v = (int32_t)le32toh((uint32_t)v); 283 m_gptr += sizeof(v); 284 return *this; 285 } 286 287 /** 288 Extract an unsigned long int from a buffer. 289 290 \param v unsigned long int to extract to. 291 \return This extractor. 292 */ operator >>(uint64_t & v)293 LeExtractor& operator >> (uint64_t& v) 294 { 295 memcpy(&v, m_gptr, sizeof(v)); 296 v = le64toh(v); 297 m_gptr += sizeof(v); 298 return *this; 299 } 300 301 /** 302 Extract a long int from a buffer. 303 304 \param v long int to extract to. 305 \return This extractor. 306 */ operator >>(int64_t & v)307 LeExtractor& operator >> (int64_t& v) 308 { 309 memcpy(&v, m_gptr, sizeof(v)); 310 v = (int64_t)le64toh((uint64_t)v); 311 m_gptr += sizeof(v); 312 return *this; 313 } 314 315 /** 316 Extract a float from a buffer. 317 318 \param v float to extract to. 319 \return This extractor. 320 */ operator >>(float & v)321 LeExtractor& operator >> (float& v) 322 { 323 memcpy(&v, m_gptr, sizeof(v)); 324 uint32_t tmp = le32toh(*(uint32_t *)(&v)); 325 memcpy(&v, &tmp, sizeof(tmp)); 326 m_gptr += sizeof(v); 327 return *this; 328 } 329 330 /** 331 Extract a double from a buffer. 332 333 \param v double to extract to. 334 \return This extractor. 335 */ operator >>(double & v)336 LeExtractor& operator >> (double& v) 337 { 338 memcpy(&v, m_gptr, sizeof(v)); 339 uint64_t tmp = le64toh(*(uint64_t *)(&v)); 340 memcpy(&v, &tmp, sizeof(tmp)); 341 m_gptr += sizeof(v); 342 return *this; 343 } 344 }; 345 346 347 /** 348 Wrapper extraction of big-endian data from a buffer to host ordering. 349 */ 350 class PDAL_DLL BeExtractor : public Extractor 351 { 352 public: 353 /** 354 Construct extractor for a buffer. 355 356 \param buf Buffer from which to extract. 357 \param size Size of buffer. 358 */ BeExtractor(const char * buf,std::size_t size)359 BeExtractor(const char *buf, std::size_t size) : Extractor(buf, size) 360 {} 361 362 /** 363 Extract an unsigned byte from a buffer. 364 365 \param v unsigned byte to extract to. 366 \return This extractor. 367 */ operator >>(uint8_t & v)368 BeExtractor& operator >> (uint8_t& v) 369 { 370 v = *(const uint8_t *)m_gptr++; 371 return *this; 372 } 373 374 /** 375 Extract a byte from a buffer. 376 377 \param v byte to extract to. 378 \return This extractor. 379 */ operator >>(int8_t & v)380 BeExtractor& operator >> (int8_t& v) 381 { 382 v = *(const int8_t *)m_gptr++; 383 return *this; 384 } 385 386 /** 387 Extract an unsigned short from a buffer. 388 389 \param v unsigned short to extract to. 390 \return This extractor. 391 */ operator >>(uint16_t & v)392 BeExtractor& operator >> (uint16_t& v) 393 { 394 memcpy(&v, m_gptr, sizeof(v)); 395 v = be16toh(v); 396 m_gptr += sizeof(v); 397 return *this; 398 } 399 400 /** 401 Extract a short from a buffer. 402 403 \param v short to extract to. 404 \return This extractor. 405 */ operator >>(int16_t & v)406 BeExtractor& operator >> (int16_t& v) 407 { 408 memcpy(&v, m_gptr, sizeof(v)); 409 v = (int16_t)be16toh((uint16_t)v); 410 m_gptr += sizeof(v); 411 return *this; 412 } 413 414 /** 415 Extract an unsigned int from a buffer. 416 417 \param v unsigned int to extract to. 418 \return This extractor. 419 */ operator >>(uint32_t & v)420 BeExtractor& operator >> (uint32_t& v) 421 { 422 memcpy(&v, m_gptr, sizeof(v)); 423 v = be32toh(v); 424 m_gptr += sizeof(v); 425 return *this; 426 } 427 428 /** 429 Extract an int from a buffer. 430 431 \param v int to extract to. 432 \return This extractor. 433 */ operator >>(int32_t & v)434 BeExtractor& operator >> (int32_t& v) 435 { 436 memcpy(&v, m_gptr, sizeof(v)); 437 v = (int32_t)be32toh((uint32_t)v); 438 m_gptr += sizeof(v); 439 return *this; 440 } 441 442 /** 443 Extract an unsigned long int from a buffer. 444 445 \param v unsigned long int to extract to. 446 \return This extractor. 447 */ operator >>(uint64_t & v)448 BeExtractor& operator >> (uint64_t& v) 449 { 450 memcpy(&v, m_gptr, sizeof(v)); 451 v = be64toh(v); 452 m_gptr += sizeof(v); 453 return *this; 454 } 455 456 /** 457 Extract a long int from a buffer. 458 459 \param v long int to extract to. 460 \return This extractor. 461 */ operator >>(int64_t & v)462 BeExtractor& operator >> (int64_t& v) 463 { 464 memcpy(&v, m_gptr, sizeof(v)); 465 v = (int64_t)be64toh((uint64_t)v); 466 m_gptr += sizeof(v); 467 return *this; 468 } 469 470 /** 471 Extract a float from a buffer. 472 473 \param v float to extract to. 474 \return This extractor. 475 */ operator >>(float & v)476 BeExtractor& operator >> (float& v) 477 { 478 memcpy(&v, m_gptr, sizeof(v)); 479 uint32_t tmp = be32toh(*(uint32_t *)(&v)); 480 memcpy(&v, &tmp, sizeof(tmp)); 481 m_gptr += sizeof(v); 482 return *this; 483 } 484 485 /** 486 Extract a double from a buffer. 487 488 \param v double to extract to. 489 \return This extractor. 490 */ operator >>(double & v)491 BeExtractor& operator >> (double& v) 492 { 493 memcpy(&v, m_gptr, sizeof(v)); 494 uint64_t tmp = be64toh(*(uint64_t *)(&v)); 495 memcpy(&v, &tmp, sizeof(tmp)); 496 m_gptr += sizeof(v); 497 return *this; 498 } 499 }; 500 501 502 /** 503 Wrapper extraction of data from a buffer to host ordering. Endianness of 504 buffered data can be specified at run-time. 505 */ 506 class PDAL_DLL SwitchableExtractor : public Extractor 507 { 508 public: 509 static const bool DefaultIsLittleEndian = true; 510 511 /** 512 Construct extractor for a buffer. 513 514 \param buf Buffer to extract from. 515 \param size Buffer size. 516 */ SwitchableExtractor(const char * buf,std::size_t size)517 SwitchableExtractor(const char* buf, std::size_t size) 518 : Extractor(buf, size) 519 , m_isLittleEndian(DefaultIsLittleEndian) 520 {} 521 522 /** 523 Construct extractor for a buffer. 524 525 \param buf Buffer to extract from. 526 \param size Buffer size. 527 \param isLittleEndian \c true if the extractor converts from little 528 endian byte order 529 */ SwitchableExtractor(const char * buf,std::size_t size,bool isLittleEndian)530 SwitchableExtractor(const char* buf, std::size_t size, bool isLittleEndian) 531 : Extractor(buf, size) 532 , m_isLittleEndian(isLittleEndian) 533 {} 534 535 /** 536 Returns whether the extractor converts from little endian. 537 538 \return \c true if the extractor converts from little endian. 539 */ isLittleEndian() const540 bool isLittleEndian() const 541 { return m_isLittleEndian; } 542 543 /** 544 Set to convert from little endian. 545 */ switchToLittleEndian()546 void switchToLittleEndian() 547 { m_isLittleEndian = true; } 548 549 /** 550 Set to convert from big endian. 551 */ switchToBigEndian()552 void switchToBigEndian() 553 { m_isLittleEndian = false; } 554 555 /** 556 Extract an unsigned byte from a buffer. 557 558 \param v unsigned byte to extract to. 559 \return This extractor. 560 */ operator >>(uint8_t & v)561 SwitchableExtractor& operator>>(uint8_t& v) 562 { 563 v = *(const uint8_t*)m_gptr++; 564 return *this; 565 } 566 567 /** 568 Extract a byte from a buffer. 569 570 \param v byte to extract to. 571 \return This extractor. 572 */ operator >>(int8_t & v)573 SwitchableExtractor& operator>>(int8_t& v) 574 { 575 v = *(const int8_t*)m_gptr++; 576 return *this; 577 } 578 579 /** 580 Extract an unsigned short from a buffer. 581 582 \param v unsigned short to extract to. 583 \return This extractor. 584 */ operator >>(uint16_t & v)585 SwitchableExtractor& operator>>(uint16_t& v) 586 { 587 memcpy(&v, m_gptr, sizeof(v)); 588 v = isLittleEndian() ? le16toh(v) : be16toh(v); 589 m_gptr += sizeof(v); 590 return *this; 591 } 592 593 /** 594 Extract a short from a buffer. 595 596 \param v short to extract to. 597 \return This extractor. 598 */ operator >>(int16_t & v)599 SwitchableExtractor& operator>>(int16_t& v) 600 { 601 memcpy(&v, m_gptr, sizeof(v)); 602 v = isLittleEndian() ? (int16_t)le16toh((uint16_t)v) 603 : (int16_t)be16toh((uint16_t)v); 604 m_gptr += sizeof(v); 605 return *this; 606 } 607 608 /** 609 Extract an unsigned int from a buffer. 610 611 \param v unsigned int to extract to. 612 \return This extractor. 613 */ operator >>(uint32_t & v)614 SwitchableExtractor& operator>>(uint32_t& v) 615 { 616 memcpy(&v, m_gptr, sizeof(v)); 617 v = isLittleEndian() ? le32toh(v) : be32toh(v); 618 m_gptr += sizeof(v); 619 return *this; 620 } 621 622 /** 623 Extract an int from a buffer. 624 625 \param v int to extract to. 626 \return This extractor. 627 */ operator >>(int32_t & v)628 SwitchableExtractor& operator>>(int32_t& v) 629 { 630 memcpy(&v, m_gptr, sizeof(v)); 631 v = isLittleEndian() ? (int32_t)le32toh((uint32_t)v) 632 : (int32_t)be32toh((uint32_t)v); 633 m_gptr += sizeof(v); 634 return *this; 635 } 636 637 /** 638 Extract an unsigned long from a buffer. 639 640 \param v unsigned long to extract to. 641 \return This extractor. 642 */ operator >>(uint64_t & v)643 SwitchableExtractor& operator>>(uint64_t& v) 644 { 645 memcpy(&v, m_gptr, sizeof(v)); 646 v = isLittleEndian() ? le64toh(v) : be64toh(v); 647 m_gptr += sizeof(v); 648 return *this; 649 } 650 651 /** 652 Extract a long from a buffer. 653 654 \param v long to extract to. 655 \return This extractor. 656 */ operator >>(int64_t & v)657 SwitchableExtractor& operator>>(int64_t& v) 658 { 659 memcpy(&v, m_gptr, sizeof(v)); 660 v = isLittleEndian() ? (int64_t)le64toh((uint64_t)v) 661 : (int64_t)be64toh((uint64_t)v); 662 m_gptr += sizeof(v); 663 return *this; 664 } 665 666 /** 667 Extract a float from a buffer. 668 669 \param v float to extract to. 670 \return This extractor. 671 */ operator >>(float & v)672 SwitchableExtractor& operator>>(float& v) 673 { 674 memcpy(&v, m_gptr, sizeof(v)); 675 uint32_t tmp = isLittleEndian() ? le32toh(*(uint32_t*)(&v)) 676 : be32toh(*(uint32_t*)(&v)); 677 memcpy(&v, &tmp, sizeof(tmp)); 678 m_gptr += sizeof(v); 679 return *this; 680 } 681 682 /** 683 Extract a double from a buffer. 684 685 \param v double to extract to. 686 \return This extractor. 687 */ operator >>(double & v)688 SwitchableExtractor& operator>>(double& v) 689 { 690 memcpy(&v, m_gptr, sizeof(v)); 691 uint64_t tmp = isLittleEndian() ? le64toh(*(uint64_t*)(&v)) 692 : be64toh(*(uint64_t*)(&v)); 693 memcpy(&v, &tmp, sizeof(tmp)); 694 m_gptr += sizeof(v); 695 return *this; 696 } 697 698 private: 699 bool m_isLittleEndian; 700 }; 701 702 } // namespace pdal 703 704