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