LCOV - code coverage report
Current view: top level - home/lbartoletti/qgis/external/laz-perf - io.hpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 218 0.0 %
Date: 2021-03-26 12:19:53 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            : ===============================================================================
       3                 :            : 
       4                 :            :   FILE:  io.hpp
       5                 :            : 
       6                 :            :   CONTENTS:
       7                 :            :     LAZ io
       8                 :            : 
       9                 :            :   PROGRAMMERS:
      10                 :            : 
      11                 :            :     martin.isenburg@rapidlasso.com  -  http://rapidlasso.com
      12                 :            :     uday.karan@gmail.com - Hobu, Inc.
      13                 :            : 
      14                 :            :   COPYRIGHT:
      15                 :            : 
      16                 :            :     (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
      17                 :            :     (c) 2014, Uday Verma, Hobu, Inc.
      18                 :            : 
      19                 :            :     This is free software; you can redistribute and/or modify it under the
      20                 :            :     terms of the GNU Lesser General Licence as published by the Free Software
      21                 :            :     Foundation. See the COPYING file for more information.
      22                 :            : 
      23                 :            :     This software is distributed WITHOUT ANY WARRANTY and without even the
      24                 :            :     implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
      25                 :            : 
      26                 :            :   CHANGE HISTORY:
      27                 :            : 
      28                 :            : ===============================================================================
      29                 :            : */
      30                 :            : 
      31                 :            : #ifndef __io_hpp__
      32                 :            : #define __io_hpp__
      33                 :            : 
      34                 :            : #include <fstream>
      35                 :            : #include <functional>
      36                 :            : #include <limits>
      37                 :            : #include <string.h>
      38                 :            : #include <mutex>
      39                 :            : 
      40                 :            : #include "formats.hpp"
      41                 :            : #include "excepts.hpp"
      42                 :            : #include "factory.hpp"
      43                 :            : #include "decoder.hpp"
      44                 :            : #include "encoder.hpp"
      45                 :            : #include "util.hpp"
      46                 :            : #include "portable_endian.hpp"
      47                 :            : 
      48                 :            : namespace laszip {
      49                 :            :         // A simple datastructure to get input from the user
      50                 :            :         template<
      51                 :            :                 typename T
      52                 :            :         >
      53                 :            :         struct vector3 {
      54                 :            :                 T x, y, z;
      55                 :            : 
      56                 :            :                 vector3() : x(0), y(0), z(0) {}
      57                 :            :                 vector3(const T& _x, const T& _y, const T& _z) :
      58                 :            :                         x(_x), y(_y), z(_z) {
      59                 :            :                 }
      60                 :            : 
      61                 :            :         };
      62                 :            : 
      63                 :            : #define DefaultChunkSize 50000
      64                 :            : 
      65                 :            :         namespace io {
      66                 :            :                 // LAZ file header
      67                 :            : #pragma pack(push, 1)
      68                 :            :                 struct header {
      69                 :            :                         char magic[4];
      70                 :            :                         unsigned short file_source_id;
      71                 :            :                         unsigned short global_encoding;
      72                 :            :                         char guid[16];
      73                 :            : 
      74                 :            :                         struct {
      75                 :            :                                 unsigned char major;
      76                 :            :                                 unsigned char minor;
      77                 :            :                         } version;
      78                 :            : 
      79                 :            :                         char system_identifier[32];
      80                 :            :                         char generating_software[32];
      81                 :            : 
      82                 :            :                         struct {
      83                 :            :                                 unsigned short day;
      84                 :            :                                 unsigned short year;
      85                 :            :                         } creation;
      86                 :            : 
      87                 :            :                         unsigned short header_size;
      88                 :            :                         unsigned int point_offset;
      89                 :            :                         unsigned int vlr_count;
      90                 :            : 
      91                 :            :                         unsigned char point_format_id;
      92                 :            :                         unsigned short point_record_length;
      93                 :            : 
      94                 :            :                         unsigned int point_count;
      95                 :            :                         unsigned int points_by_return[5];
      96                 :            : 
      97                 :            :                         struct {
      98                 :            :                                 double x, y, z;
      99                 :            :                         } scale;
     100                 :            : 
     101                 :            :                         struct {
     102                 :            :                                 double x, y, z;
     103                 :            :                         } offset;
     104                 :            : 
     105                 :            :                         struct {
     106                 :            :                                 double x, y, z;
     107                 :            :                         } minimum;
     108                 :            : 
     109                 :            :                         struct {
     110                 :            :                                 double x, y, z;
     111                 :            :                         } maximum;
     112                 :            :                 };
     113                 :            : 
     114                 :            :                 // A Single LAZ Item representation
     115                 :            :                 struct laz_item {
     116                 :            :                         unsigned short type,
     117                 :            :                                                    size,
     118                 :            :                                                    version;
     119                 :            :                 };
     120                 :            : 
     121                 :            :                 struct laz_vlr {
     122                 :            :                         uint16_t compressor;
     123                 :            :                         uint16_t coder;
     124                 :            : 
     125                 :            :                         struct {
     126                 :            :                                 unsigned char major;
     127                 :            :                                 unsigned char minor;
     128                 :            :                                 uint16_t revision;
     129                 :            :                         } version;
     130                 :            : 
     131                 :            :                         uint32_t options;
     132                 :            :                         uint32_t chunk_size;
     133                 :            : 
     134                 :            :                         int64_t num_points,
     135                 :            :                                         num_bytes;
     136                 :            : 
     137                 :            :                         uint16_t num_items;
     138                 :            :                         laz_item *items;
     139                 :          0 :                         laz_vlr() : num_items(0), items(NULL) {}
     140                 :          0 :                         ~laz_vlr() {
     141                 :          0 :                 delete [] items;
     142                 :          0 :                         }
     143                 :            : 
     144                 :            :             laz_vlr(const char *data) {
     145                 :            :                 items = NULL;
     146                 :            :                 fill(data);
     147                 :            :             }
     148                 :            : 
     149                 :            :             size_t size() const {
     150                 :            :                 return sizeof(laz_vlr) - sizeof(laz_item *) +
     151                 :            :                     (num_items * sizeof(laz_item));
     152                 :            :             }
     153                 :            : 
     154                 :            :                         laz_vlr(const laz_vlr& rhs) {
     155                 :            :                                 compressor = rhs.compressor;
     156                 :            :                                 coder = rhs.coder;
     157                 :            : 
     158                 :            :                                 // the version we're compatible with
     159                 :            :                                 version.major = rhs.version.major;
     160                 :            :                                 version.minor = rhs.version.minor;
     161                 :            :                                 version.revision = rhs.version.revision;
     162                 :            : 
     163                 :            :                                 options = rhs.options;
     164                 :            :                                 chunk_size = rhs.chunk_size;
     165                 :            : 
     166                 :            :                                 num_points = rhs.num_points;
     167                 :            :                                 num_bytes = rhs.num_bytes;
     168                 :            : 
     169                 :            :                                 num_items = rhs.num_items;
     170                 :            :                                 if (rhs.items) {
     171                 :            :                                         items = new laz_item[num_items];
     172                 :            :                                         for (int i = 0 ; i < num_items ; i ++) {
     173                 :            :                                                 items[i] = rhs.items[i];
     174                 :            :                                         }
     175                 :            :                                 }
     176                 :            :                         }
     177                 :            : 
     178                 :            :                         laz_vlr& operator = (const laz_vlr& rhs) {
     179                 :            :                                 if (this == &rhs)
     180                 :            :                                         return *this;
     181                 :            : 
     182                 :            :                                 compressor = rhs.compressor;
     183                 :            :                                 coder = rhs.coder;
     184                 :            : 
     185                 :            :                                 // the version we're compatible with
     186                 :            :                                 version.major = rhs.version.major;
     187                 :            :                                 version.minor = rhs.version.minor;
     188                 :            :                                 version.revision = rhs.version.revision;
     189                 :            : 
     190                 :            :                                 options = rhs.options;
     191                 :            :                                 chunk_size = rhs.chunk_size;
     192                 :            : 
     193                 :            :                                 num_points = rhs.num_points;
     194                 :            :                                 num_bytes = rhs.num_bytes;
     195                 :            : 
     196                 :            :                                 num_items = rhs.num_items;
     197                 :            :                                 if (rhs.items) {
     198                 :            :                                         items = new laz_item[num_items];
     199                 :            :                                         for (int i = 0 ; i < num_items ; i ++) {
     200                 :            :                                                 items[i] = rhs.items[i];
     201                 :            :                                         }
     202                 :            :                                 }
     203                 :            : 
     204                 :            :                                 return *this;
     205                 :            :                         }
     206                 :            : 
     207                 :          0 :             void fill(const char *data) {
     208                 :          0 :                 std::copy(data, data + sizeof(compressor), (char *)&compressor);
     209                 :          0 :                 compressor = le16toh(compressor);
     210                 :          0 :                 data += sizeof(compressor);
     211                 :            : 
     212                 :          0 :                 std::copy(data, data + sizeof(coder), (char *)&coder);
     213                 :          0 :                 coder = le16toh(coder);
     214                 :          0 :                 data += sizeof(coder);
     215                 :            : 
     216                 :          0 :                 version.major = *(const unsigned char *)data++;
     217                 :          0 :                 version.minor = *(const unsigned char *)data++;
     218                 :            : 
     219                 :          0 :                 std::copy(data, data + sizeof(version.revision), (char *)&version.revision);
     220                 :          0 :                 version.revision = le16toh(version.revision);
     221                 :          0 :                 data += sizeof(version.revision);
     222                 :            : 
     223                 :          0 :                 std::copy(data, data + sizeof(options), (char *)&options);
     224                 :          0 :                 options = le32toh(options);
     225                 :          0 :                 data += sizeof(options);
     226                 :            : 
     227                 :          0 :                 std::copy(data, data + sizeof(chunk_size), (char *)&chunk_size);
     228                 :          0 :                 chunk_size = le32toh(chunk_size);
     229                 :          0 :                 data += sizeof(chunk_size);
     230                 :            : 
     231                 :          0 :                 std::copy(data, data + sizeof(num_points), (char *)&num_points);
     232                 :          0 :                 num_points = le64toh(num_points);
     233                 :          0 :                 data += sizeof(num_points);
     234                 :            : 
     235                 :          0 :                 std::copy(data, data + sizeof(num_bytes), (char *)&num_bytes);
     236                 :          0 :                 num_bytes = le64toh(num_bytes);
     237                 :          0 :                 data += sizeof(num_bytes);
     238                 :            : 
     239                 :          0 :                 std::copy(data, data + sizeof(num_items), (char *)&num_items);
     240                 :          0 :                 num_items = le16toh(num_items);
     241                 :          0 :                 data += sizeof(num_items);
     242                 :            : 
     243                 :          0 :                 delete [] items;
     244                 :          0 :                         items = new laz_item[num_items];
     245                 :          0 :                 for (int i = 0 ; i < num_items ; i ++) {
     246                 :          0 :                     laz_item& item = items[i];
     247                 :            : 
     248                 :          0 :                     std::copy(data, data + sizeof(item.type), (char *)&item.type);
     249                 :          0 :                     item.type = le16toh(item.type);
     250                 :          0 :                     data += sizeof(item.type);
     251                 :            : 
     252                 :          0 :                     std::copy(data, data + sizeof(item.size), (char *)&item.size);
     253                 :          0 :                     item.size = le16toh(item.size);
     254                 :          0 :                     data += sizeof(item.size);
     255                 :            : 
     256                 :          0 :                     std::copy(data, data + sizeof(item.version), (char *)&item.version);
     257                 :          0 :                     item.version = le16toh(item.version);
     258                 :          0 :                     data += sizeof(item.version);
     259                 :          0 :                 }
     260                 :          0 :             }
     261                 :            : 
     262                 :            :             void extract(char *data) {
     263                 :            :                 uint16_t s;
     264                 :            :                 uint32_t i;
     265                 :            :                 uint64_t ll;
     266                 :            :                 char *src;
     267                 :            : 
     268                 :            :                 s = htole16(compressor);
     269                 :            :                 src = (char *)&s;
     270                 :            :                 std::copy(src, src + sizeof(compressor), data);
     271                 :            :                 data += sizeof(compressor);
     272                 :            : 
     273                 :            :                 s = htole16(coder);
     274                 :            :                 src = (char *)&s;
     275                 :            :                 std::copy(src, src + sizeof(coder), data);
     276                 :            :                 data += sizeof(coder);
     277                 :            : 
     278                 :            :                 *data++ = version.major;
     279                 :            :                 *data++ = version.minor;
     280                 :            : 
     281                 :            :                 s = htole16(version.revision);
     282                 :            :                 src = (char *)&s;
     283                 :            :                 std::copy(src, src + sizeof(version.revision), data);
     284                 :            :                 data += sizeof(version.revision);
     285                 :            : 
     286                 :            :                 i = htole32(options);
     287                 :            :                 src = (char *)&i;
     288                 :            :                 std::copy(src, src + sizeof(options), data);
     289                 :            :                 data += sizeof(options);
     290                 :            : 
     291                 :            :                 i = htole32(chunk_size);
     292                 :            :                 src = (char *)&i;
     293                 :            :                 std::copy(src, src + sizeof(chunk_size), data);
     294                 :            :                 data += sizeof(chunk_size);
     295                 :            : 
     296                 :            :                 ll = htole64(num_points);
     297                 :            :                 src = (char *)&ll;
     298                 :            :                 std::copy(src, src + sizeof(num_points), data);
     299                 :            :                 data += sizeof(num_points);
     300                 :            : 
     301                 :            :                 ll = htole64(num_bytes);
     302                 :            :                 src = (char *)&ll;
     303                 :            :                 std::copy(src, src + sizeof(num_bytes), data);
     304                 :            :                 data += sizeof(num_bytes);
     305                 :            : 
     306                 :            :                 s = htole16(num_items);
     307                 :            :                 src = (char *)&s;
     308                 :            :                 std::copy(src, src + sizeof(num_items), data);
     309                 :            :                 data += sizeof(num_items);
     310                 :            : 
     311                 :            :                 for (int k = 0 ; k < num_items ; k ++) {
     312                 :            :                     laz_item& item = items[k];
     313                 :            : 
     314                 :            :                     s = htole16(item.type);
     315                 :            :                     src = (char *)&s;
     316                 :            :                     std::copy(src, src + sizeof(item.type), data);
     317                 :            :                     data += sizeof(item.type);
     318                 :            : 
     319                 :            :                     s = htole16(item.size);
     320                 :            :                     src = (char *)&s;
     321                 :            :                     std::copy(src, src + sizeof(item.size), data);
     322                 :            :                     data += sizeof(item.size);
     323                 :            : 
     324                 :            :                     s = htole16(item.version);
     325                 :            :                     src = (char *)&s;
     326                 :            :                     std::copy(src, src + sizeof(item.version), data);
     327                 :            :                     data += sizeof(item.version);
     328                 :            :                 }
     329                 :            :             }
     330                 :            : 
     331                 :            :                         static laz_vlr from_schema(const factory::record_schema& s, uint32_t chunksize = DefaultChunkSize) {
     332                 :            :                                 laz_vlr r;
     333                 :            : 
     334                 :            :                 // We only do pointwise chunking.
     335                 :            :                                 r.compressor = 2;
     336                 :            :                                 r.coder = 0;
     337                 :            : 
     338                 :            :                                 // the version we're compatible with
     339                 :            :                                 r.version.major = 2;
     340                 :            :                                 r.version.minor = 2;
     341                 :            :                                 r.version.revision = 0;
     342                 :            : 
     343                 :            :                                 r.options = 0;
     344                 :            :                                 r.chunk_size = chunksize;
     345                 :            : 
     346                 :            :                                 r.num_points = -1;
     347                 :            :                                 r.num_bytes = -1;
     348                 :            : 
     349                 :            :                                 r.num_items = static_cast<unsigned short>(s.records.size());
     350                 :            :                                 r.items = new laz_item[s.records.size()];
     351                 :            :                                 for (size_t i = 0 ; i < s.records.size() ; i ++) {
     352                 :            :                                         laz_item& item = r.items[i];
     353                 :            :                                         const factory::record_item& rec = s.records.at(i);
     354                 :            : 
     355                 :            :                                         item.type = static_cast<unsigned short>(rec.type);
     356                 :            :                                         item.size = static_cast<unsigned short>(rec.size);
     357                 :            :                                         item.version = static_cast<unsigned short>(rec.version);
     358                 :            :                                 }
     359                 :            : 
     360                 :            :                                 return r;
     361                 :            :                         }
     362                 :            : 
     363                 :          0 :             static factory::record_schema to_schema(const laz_vlr& vlr, int point_len) {
     364                 :            :                 // convert the laszip items into record schema to be used by
     365                 :            :                 // compressor/decompressor
     366                 :            : 
     367                 :            :                 using namespace factory;
     368                 :          0 :                 factory::record_schema schema;
     369                 :            : 
     370                 :          0 :                 for(auto i = 0 ; i < vlr.num_items ; i++) {
     371                 :          0 :                     laz_item& item = vlr.items[i];
     372                 :          0 :                     schema.push(factory::record_item(item.type, item.size,
     373                 :          0 :                         item.version));
     374                 :          0 :                     point_len -= item.size;
     375                 :          0 :                 }
     376                 :          0 :                 if (point_len < 0)
     377                 :          0 :                     throw laszip_format_unsupported();
     378                 :            :                 // Add extra bytes information
     379                 :          0 :                 if (point_len)
     380                 :          0 :                     schema.push(factory::record_item(record_item::BYTE,
     381                 :          0 :                         point_len, 2));
     382                 :          0 :                 return schema;
     383                 :          0 :             }
     384                 :            : 
     385                 :            : #ifdef _WIN32
     386                 :            :             __declspec(deprecated) static factory::record_schema to_schema(const laz_vlr& vlr)
     387                 :            : #else
     388                 :            :             static factory::record_schema to_schema(const laz_vlr& vlr) __attribute__ ((deprecated))
     389                 :            : #endif
     390                 :            :             {
     391                 :            :                 // convert the laszip items into record schema to be used by
     392                 :            :                 // compressor/decompressor
     393                 :            : 
     394                 :            :                 using namespace factory;
     395                 :            :                 factory::record_schema schema;
     396                 :            : 
     397                 :            :                 for(auto i = 0 ; i < vlr.num_items ; i++) {
     398                 :            :                     laz_item& item = vlr.items[i];
     399                 :            :                     schema.push(factory::record_item(item.type, item.size,
     400                 :            :                         item.version));
     401                 :            :                 }
     402                 :            :                 return schema;
     403                 :            :             }
     404                 :            :                 };
     405                 :            : #pragma pack(pop)
     406                 :            : 
     407                 :            :                 // cache line
     408                 :            : #define BUF_SIZE (1 << 20)
     409                 :            : 
     410                 :            :                 template<typename StreamType>
     411                 :            :                 struct __ifstream_wrapper {
     412                 :          0 :                         __ifstream_wrapper(StreamType& f) : f_(f), offset(0), have(0),
     413                 :          0 :                                 buf_((char*)utils::aligned_malloc(BUF_SIZE)) {
     414                 :          0 :                         }
     415                 :            : 
     416                 :          0 :                         ~__ifstream_wrapper() {
     417                 :          0 :                                 utils::aligned_free(buf_);
     418                 :          0 :                         }
     419                 :            : 
     420                 :            :                         __ifstream_wrapper(const __ifstream_wrapper<StreamType>&) = delete;
     421                 :            :                         __ifstream_wrapper& operator = (const __ifstream_wrapper<StreamType>&) = delete;
     422                 :            : 
     423                 :          0 :                         inline void fillit_() {
     424                 :          0 :                                 offset = 0;
     425                 :          0 :                                 f_.read(buf_, BUF_SIZE);
     426                 :          0 :                                 have = f_.gcount();
     427                 :          0 :                                 if (have == 0)
     428                 :          0 :                                         throw end_of_file(); // this is an exception since we shouldn't be hitting eof
     429                 :          0 :                         }
     430                 :            : 
     431                 :          0 :                         inline void reset() {
     432                 :          0 :                                 offset = have = 0; // when a file is seeked, reset this
     433                 :          0 :                         }
     434                 :            : 
     435                 :          0 :                         inline unsigned char getByte() {
     436                 :          0 :                 if (offset >= have)
     437                 :          0 :                     fillit_();
     438                 :          0 :                                 return static_cast<unsigned char>(buf_[offset++]);
     439                 :            :                         }
     440                 :            : 
     441                 :          0 :                         inline void getBytes(unsigned char *buf, size_t request) {
     442                 :            :                 // Use what's left in the buffer, if anything.
     443                 :          0 :                 size_t fetchable = (std::min)((size_t)(have - offset), request);
     444                 :          0 :                                 std::copy(buf_ + offset, buf_ + offset + fetchable, buf);
     445                 :          0 :                 offset += fetchable;
     446                 :          0 :                 request -= fetchable;
     447                 :            : 
     448                 :            :                 // If we couldn't fetch everything requested, fill buffer
     449                 :            :                 // and go again.  We assume fillit_() satisfies any request.
     450                 :          0 :                 if (request)
     451                 :            :                 {
     452                 :          0 :                     fillit_();
     453                 :          0 :                                     std::copy(buf_ + offset, buf_ + offset + request, buf + fetchable);
     454                 :          0 :                                     offset += request;
     455                 :          0 :                 }
     456                 :          0 :                         }
     457                 :            : 
     458                 :            :                         StreamType& f_;
     459                 :            :                         std::streamsize offset, have;
     460                 :            :                         char *buf_;
     461                 :            :                 };
     462                 :            : 
     463                 :            :         template<typename StreamType>
     464                 :            :                 struct __ofstream_wrapper {
     465                 :            :                         __ofstream_wrapper(StreamType& f) : f_(f) {}
     466                 :            : 
     467                 :            :                         void putBytes(const unsigned char *b, size_t len) {
     468                 :            :                                 f_.write(reinterpret_cast<const char*>(b), len);
     469                 :            :                         }
     470                 :            : 
     471                 :            :                         void putByte(unsigned char b) {
     472                 :            :                                 f_.put((char)b);
     473                 :            :                         }
     474                 :            : 
     475                 :            :                         __ofstream_wrapper(const __ofstream_wrapper&) = delete;
     476                 :            :                         __ofstream_wrapper& operator = (const __ofstream_wrapper&) = delete;
     477                 :            : 
     478                 :            :                         StreamType& f_;
     479                 :            :                 };
     480                 :            : 
     481                 :            :                 namespace reader {
     482                 :            :                         template <typename StreamType>
     483                 :            :                         class basic_file {
     484                 :            :                                 typedef std::function<void (header&)> validator_type;
     485                 :            : 
     486                 :            :                                 public:
     487                 :          0 :                                 basic_file(StreamType& st) : f_(st), wrapper_(f_) {
     488                 :          0 :                                         _open();
     489                 :          0 :                                 }
     490                 :            : 
     491                 :          0 :                                 ~basic_file() {
     492                 :          0 :                                 }
     493                 :            : 
     494                 :          0 :                                 const header& get_header() const {
     495                 :          0 :                                         return header_;
     496                 :            :                                 }
     497                 :            : 
     498                 :            :                                 const laz_vlr& get_laz_vlr() const {
     499                 :            :                                         return laz_;
     500                 :            :                                 }
     501                 :            : 
     502                 :            :                                 const factory::record_schema& get_schema() const {
     503                 :            :                                         return schema_;
     504                 :            :                                 }
     505                 :            : 
     506                 :          0 :                                 void readPoint(char *out) {
     507                 :            :                                         // read the next point in
     508                 :          0 :                                         if (chunk_state_.points_read == laz_.chunk_size ||
     509                 :          0 :                                                         !pdecomperssor_ || !pdecoder_) {
     510                 :            :                                                 // Its time to (re)init the decoder
     511                 :            :                                                 //
     512                 :          0 :                                                 pdecomperssor_.reset();
     513                 :          0 :                                                 pdecoder_.reset();
     514                 :            : 
     515                 :          0 :                                                 pdecoder_.reset(new decoders::arithmetic<__ifstream_wrapper<StreamType> >(wrapper_));
     516                 :          0 :                                                 pdecomperssor_ = factory::build_decompressor(*pdecoder_, schema_);
     517                 :            : 
     518                 :            :                                                 // reset chunk state
     519                 :          0 :                                                 chunk_state_.current++;
     520                 :          0 :                                                 chunk_state_.points_read = 0;
     521                 :          0 :                                         }
     522                 :            : 
     523                 :          0 :                                         pdecomperssor_->decompress(out);
     524                 :          0 :                                         chunk_state_.points_read ++;
     525                 :          0 :                                 }
     526                 :            : 
     527                 :            :                                 private:
     528                 :          0 :                                 void _open() {
     529                 :            :                                         // Make sure our header is correct
     530                 :            :                                         //
     531                 :            :                                         char magic[4];
     532                 :          0 :                                         f_.read(magic, sizeof(magic));
     533                 :            : 
     534                 :          0 :                                         if (std::string(magic, magic+4) != "LASF")
     535                 :          0 :                                                 throw invalid_magic();
     536                 :            : 
     537                 :            :                                         // Read the header in
     538                 :          0 :                                         f_.seekg(0);
     539                 :          0 :                                         f_.read((char*)&header_, sizeof(header_));
     540                 :            : 
     541                 :            :                                         // The mins and maxes are in a weird order, fix them
     542                 :          0 :                                         _fixMinMax(header_);
     543                 :            : 
     544                 :            :                                         // make sure everything is valid with the header, note that validators are allowed
     545                 :            :                                         // to manipulate the header, since certain validators depend on a header's orignial state
     546                 :            :                                         // to determine what its final stage is going to be
     547                 :          0 :                                         for (auto f : _validators())
     548                 :          0 :                                                 f(header_);
     549                 :            : 
     550                 :            :                                         // things look fine, move on with VLR extraction
     551                 :          0 :                                         _parseLASZIP();
     552                 :            : 
     553                 :            :                                         // parse the chunk table offset
     554                 :          0 :                                         _parseChunkTable();
     555                 :            : 
     556                 :            :                                         // set the file pointer to the beginning of data to start reading
     557                 :          0 :                                         f_.clear(); // may have treaded past the EOL, so reset everything before we start reading:w
     558                 :          0 :                                         f_.seekg(header_.point_offset + sizeof(int64_t));
     559                 :            : 
     560                 :          0 :                                         wrapper_.reset();
     561                 :          0 :                                 }
     562                 :            : 
     563                 :          0 :                                 void _fixMinMax(header& h) {
     564                 :            :                                         double mx, my, mz, nx, ny, nz;
     565                 :            : 
     566                 :          0 :                                         mx = h.minimum.x; nx = h.minimum.y;
     567                 :          0 :                                         my = h.minimum.z; ny = h.maximum.x;
     568                 :          0 :                                         mz = h.maximum.y; nz = h.maximum.z;
     569                 :            : 
     570                 :          0 :                                         h.minimum.x = nx; h.maximum.x = mx;
     571                 :          0 :                                         h.minimum.y = ny; h.maximum.y = my;
     572                 :          0 :                                         h.minimum.z = nz; h.maximum.z = mz;
     573                 :          0 :                                 }
     574                 :            : 
     575                 :          0 :                                 void _parseLASZIP() {
     576                 :            :                                         // move the pointer to the begining of the VLRs
     577                 :          0 :                                         f_.seekg(header_.header_size);
     578                 :            : 
     579                 :            : #pragma pack(push, 1)
     580                 :            :                                         struct {
     581                 :            :                                                 unsigned short reserved;
     582                 :            :                                                 char user_id[16];
     583                 :            :                                                 unsigned short record_id;
     584                 :            :                                                 unsigned short record_length;
     585                 :            :                                                 char desc[32];
     586                 :            :                                         } vlr_header;
     587                 :            : #pragma pack(pop)
     588                 :            : 
     589                 :          0 :                                         size_t count = 0;
     590                 :          0 :                                         bool laszipFound = false;
     591                 :          0 :                                         while(count < header_.vlr_count && f_.good() && !f_.eof()) {
     592                 :          0 :                                                 f_.read((char*)&vlr_header, sizeof(vlr_header));
     593                 :            : 
     594                 :          0 :                                                 const char *user_id = "laszip encoded";
     595                 :            : 
     596                 :          0 :                                                 if (std::equal(vlr_header.user_id, vlr_header.user_id + 14, user_id) &&
     597                 :          0 :                                                                 vlr_header.record_id == 22204) {
     598                 :            :                                                         // this is the laszip VLR
     599                 :            :                                                         //
     600                 :          0 :                                                         laszipFound = true;
     601                 :            : 
     602                 :          0 :                                                         std::unique_ptr<char> buffer(
     603                 :          0 :                                 new char[vlr_header.record_length]);
     604                 :            : 
     605                 :          0 :                                                         f_.read(buffer.get(), vlr_header.record_length);
     606                 :          0 :                                                         _parseLASZIPVLR(buffer.get());
     607                 :            : 
     608                 :            :                                                         break; // no need to keep iterating
     609                 :          0 :                                                 }
     610                 :            : 
     611                 :          0 :                                                 f_.seekg(vlr_header.record_length, std::ios::cur); // jump foward
     612                 :          0 :                                                 count++;
     613                 :            :                                         }
     614                 :            : 
     615                 :          0 :                                         if (!laszipFound)
     616                 :          0 :                                                 throw no_laszip_vlr();
     617                 :            : 
     618                 :          0 :                     schema_ = laz_vlr::to_schema(laz_, header_.point_record_length);
     619                 :          0 :                                 }
     620                 :            : 
     621                 :            :                                 void binPrint(const char *buf, int len) {
     622                 :            :                                         for (int i = 0 ; i < len ; i ++) {
     623                 :            :                                                 char b[256];
     624                 :            :                                                 sprintf(b, "%02X", buf[i] & 0xFF);
     625                 :            :                                                 std::cout << b << " ";
     626                 :            :                                         }
     627                 :            : 
     628                 :            :                                         std::cout << std::endl;
     629                 :            :                                 }
     630                 :            : 
     631                 :          0 :                                 void _parseLASZIPVLR(const char *buf) {
     632                 :          0 :                     laz_.fill(buf);
     633                 :            : 
     634                 :          0 :                                         if (laz_.compressor != 2)
     635                 :          0 :                                                 throw laszip_format_unsupported();
     636                 :          0 :                                 }
     637                 :            : 
     638                 :          0 :                                 void _parseChunkTable() {
     639                 :            :                                         // Move to the begining of the data
     640                 :            :                                         //
     641                 :          0 :                                         f_.seekg(header_.point_offset);
     642                 :            : 
     643                 :          0 :                                         int64_t chunkoffset = 0;
     644                 :          0 :                                         f_.read((char*)&chunkoffset, sizeof(chunkoffset));
     645                 :          0 :                                         if (!f_.good())
     646                 :          0 :                                                 throw chunk_table_read_error();
     647                 :            : 
     648                 :          0 :                                         if (chunkoffset == -1)
     649                 :          0 :                                                 throw not_supported("Chunk table offset == -1 is not supported at this time");
     650                 :            : 
     651                 :            :                                         // Go to the chunk offset and read in the table
     652                 :            :                                         //
     653                 :          0 :                                         f_.seekg(chunkoffset);
     654                 :          0 :                                         if (!f_.good())
     655                 :          0 :                                                 throw chunk_table_read_error();
     656                 :            : 
     657                 :            :                                         // Now read in the chunk table
     658                 :            :                                         struct {
     659                 :            :                                                 unsigned int version,
     660                 :            :                                                                          chunk_count;
     661                 :            :                                         } chunk_table_header;
     662                 :            : 
     663                 :          0 :                                         f_.read((char *)&chunk_table_header, sizeof(chunk_table_header));
     664                 :          0 :                                         if (!f_.good())
     665                 :          0 :                                                 throw chunk_table_read_error();
     666                 :            : 
     667                 :          0 :                                         if (chunk_table_header.version != 0)
     668                 :          0 :                                                 throw unknown_chunk_table_format();
     669                 :            : 
     670                 :            :                                         // start pushing in chunk table offsets
     671                 :          0 :                                         chunk_table_offsets_.clear();
     672                 :            : 
     673                 :          0 :                                         if (laz_.chunk_size == (std::numeric_limits<unsigned int>::max)())
     674                 :          0 :                                                 throw not_supported("chunk_size == uint.max is not supported at this time.");
     675                 :            : 
     676                 :            :                                         // Allocate enough room for our chunk
     677                 :          0 :                                         chunk_table_offsets_.resize(chunk_table_header.chunk_count + 1);
     678                 :            : 
     679                 :            :                                         // Add The first one
     680                 :          0 :                                         chunk_table_offsets_[0] = header_.point_offset + sizeof(uint64_t);
     681                 :            : 
     682                 :          0 :                                         if (chunk_table_header.chunk_count > 1) {
     683                 :            :                                                 // decode the index out
     684                 :            :                                                 //
     685                 :          0 :                                                 __ifstream_wrapper<StreamType> w(f_);
     686                 :            : 
     687                 :          0 :                                                 decoders::arithmetic<__ifstream_wrapper<StreamType> > decoder(w);
     688                 :          0 :                                                 decompressors::integer decomp(32, 2);
     689                 :            : 
     690                 :            :                                                 // start decoder
     691                 :          0 :                                                 decoder.readInitBytes();
     692                 :          0 :                                                 decomp.init();
     693                 :            : 
     694                 :          0 :                                                 for (size_t i = 1 ; i <= chunk_table_header.chunk_count ; i ++) {
     695                 :          0 :                                                         chunk_table_offsets_[i] = static_cast<uint64_t>(decomp.decompress(decoder, (i > 1) ? static_cast<I32>(chunk_table_offsets_[i - 1]) : 0, 1));
     696                 :          0 :                                                 }
     697                 :            : 
     698                 :          0 :                                                 for (size_t i = 1 ; i < chunk_table_offsets_.size() ; i ++) {
     699                 :          0 :                                                         chunk_table_offsets_[i] += chunk_table_offsets_[i-1];
     700                 :          0 :                                                 }
     701                 :          0 :                                         }
     702                 :          0 :                                 }
     703                 :            : 
     704                 :            : 
     705                 :          0 :                                 static const std::vector<validator_type>& _validators() {
     706                 :          0 :                                         static std::vector<validator_type> v; // static collection of validators
     707                 :          0 :                                         static std::mutex lock;
     708                 :            : 
     709                 :            :                                         // To remain thread safe we need to make sure we have appropriate guards here
     710                 :            :                                         //
     711                 :          0 :                                         if (v.empty()) {
     712                 :          0 :                                                 lock.lock();
     713                 :            :                                                 // Double check here if we're still empty, the first empty just makes sure
     714                 :            :                                                 // we have a quick way out where validators are already filled up (for all calls
     715                 :            :                                                 // except the first one), for two threads competing to fill out the validators
     716                 :            :                                                 // only one of the will get here first, and the second one will bail if the v
     717                 :            :                                                 // is not empty, and hence the double check
     718                 :            :                                                 //
     719                 :          0 :                                                 if (v.empty()) {
     720                 :            :                                                         // TODO: Fill all validators here
     721                 :            :                                                         //
     722                 :          0 :                                                         v.push_back(
     723                 :            :                                                                         // Make sure that the header indicates that file is compressed
     724                 :            :                                                                         //
     725                 :          0 :                                                                         [](header& h) {
     726                 :          0 :                                                                                 int bit_7 = (h.point_format_id >> 7) & 1,
     727                 :          0 :                                                                                         bit_6 = (h.point_format_id >> 6) & 1;
     728                 :            : 
     729                 :          0 :                                                                                 if (bit_7 == 1 && bit_6 == 1)
     730                 :          0 :                                                                                         throw old_style_compression();
     731                 :            : 
     732                 :          0 :                                                                                 if ((bit_7 ^ bit_6) == 0)
     733                 :          0 :                                                                                         throw not_compressed();
     734                 :            : 
     735                 :          0 :                                                                                 h.point_format_id &= 0x3f;
     736                 :          0 :                                                                         }
     737                 :            :                                                         );
     738                 :          0 :                                                 }
     739                 :            : 
     740                 :          0 :                                                 lock.unlock();
     741                 :          0 :                                         }
     742                 :            : 
     743                 :          0 :                                         return v;
     744                 :          0 :                                 }
     745                 :            : 
     746                 :            :                                 // The file object is not copyable or copy constructible
     747                 :            :                                 basic_file(const basic_file<StreamType>&) = delete;
     748                 :            :                                 basic_file<StreamType>& operator = (const basic_file<StreamType>&) = delete;
     749                 :            : 
     750                 :            :                                 StreamType& f_;
     751                 :            :                                 __ifstream_wrapper<StreamType> wrapper_;
     752                 :            : 
     753                 :            :                                 header header_;
     754                 :            :                                 laz_vlr laz_;
     755                 :            :                                 std::vector<uint64_t> chunk_table_offsets_;
     756                 :            : 
     757                 :            :                                 factory::record_schema schema_; // the schema of this file, the LAZ items converted into factory recognizable description,
     758                 :            : 
     759                 :            :                                 // Our decompressor
     760                 :            :                                 std::shared_ptr<decoders::arithmetic<__ifstream_wrapper<StreamType> > > pdecoder_;
     761                 :            :                                 formats::dynamic_decompressor::ptr pdecomperssor_;
     762                 :            : 
     763                 :            :                                 // Establish our current state as we iterate through the file
     764                 :            :                                 struct __chunk_state{
     765                 :            :                                         int64_t current;
     766                 :            :                                         int64_t points_read;
     767                 :            :                                         int64_t current_index;
     768                 :            : 
     769                 :          0 :                                         __chunk_state() : current(0u), points_read(0u), current_index(-1) {}
     770                 :            :                                 } chunk_state_;
     771                 :            :                         };
     772                 :            : 
     773                 :            :                         typedef basic_file<std::ifstream> file;
     774                 :            :                 }
     775                 :            : 
     776                 :            :                 namespace writer {
     777                 :            : 
     778                 :            :                         // An object to encapsulate what gets passed to
     779                 :            :                         struct config {
     780                 :            :                                 vector3<double> scale, offset;
     781                 :            :                                 unsigned int chunk_size;
     782                 :            : 
     783                 :            :                                 explicit config() : scale(1.0, 1.0, 1.0), offset(0.0, 0.0, 0.0), chunk_size(DefaultChunkSize) {}
     784                 :            :                                 config(const vector3<double>& s, const vector3<double>& o, unsigned int cs = DefaultChunkSize) :
     785                 :            :                                         scale(s), offset(o), chunk_size(cs) {}
     786                 :            :                 config(const header& h) : scale(h.scale.x, h.scale.y, h.scale.z), offset(h.offset.x, h.offset.y, h.offset.z),
     787                 :            :                     chunk_size(DefaultChunkSize) {}
     788                 :            : 
     789                 :            :                                 header to_header() const {
     790                 :            :                                         header h; memset(&h, 0, sizeof(h)); // clear out header
     791                 :            :                                         h.minimum = { (std::numeric_limits<double>::max)(), (std::numeric_limits<double>::max)(),
     792                 :            :                         (std::numeric_limits<double>::max)() };
     793                 :            :                                         h.maximum = { std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(),
     794                 :            :                         std::numeric_limits<double>::lowest()};
     795                 :            : 
     796                 :            :                                         h.offset.x = offset.x;
     797                 :            :                                         h.offset.y = offset.y;
     798                 :            :                                         h.offset.z = offset.z;
     799                 :            : 
     800                 :            :                                         h.scale.x = scale.x;
     801                 :            :                                         h.scale.y = scale.y;
     802                 :            :                                         h.scale.z = scale.z;
     803                 :            : 
     804                 :            :                                         return h;
     805                 :            :                                 }
     806                 :            :                         };
     807                 :            : 
     808                 :            :                         class file {
     809                 :            :                         public:
     810                 :            :                                 file() :
     811                 :            :                                         wrapper_(f_) {}
     812                 :            : 
     813                 :            :                                 file(const std::string& filename,
     814                 :            :                                                 const factory::record_schema& s,
     815                 :            :                                                 const config& config) :
     816                 :            :                                         wrapper_(f_),
     817                 :            :                                         schema_(s),
     818                 :            :                                         header_(config.to_header()),
     819                 :            :                                         chunk_size_(config.chunk_size) {
     820                 :            :                                                 open(filename, s, config);
     821                 :            :                                 }
     822                 :            : 
     823                 :            :                                 void open(const std::string& filename, const factory::record_schema& s, const config& c) {
     824                 :            :                                         // open the file and move to offset of data, we'll write
     825                 :            :                                         // headers and all other things on file close
     826                 :            :                                         f_.open(filename, std::ios::binary | std::ios::trunc);
     827                 :            :                                         if (!f_.good())
     828                 :            :                                                 throw write_open_failed();
     829                 :            : 
     830                 :            :                                         schema_ = s;
     831                 :            :                                         header_ = c.to_header();
     832                 :            :                                         chunk_size_ = c.chunk_size;
     833                 :            : 
     834                 :            :                                         // write junk to our prelude, we'll overwrite this with
     835                 :            :                                         // awesome data later
     836                 :            :                                         //
     837                 :            :                                         size_t preludeSize =
     838                 :            :                                                 sizeof(header) +        // the LAS header
     839                 :            :                                                 54 + // size of one vlr header
     840                 :            :                                                 (34 + s.records.size() * 6) + // the LAZ vlr size
     841                 :            :                                                 sizeof(int64_t); // chunk table offset
     842                 :            : 
     843                 :            :                                         char *junk = new char[preludeSize];
     844                 :            :                                         std::fill(junk, junk + preludeSize, 0);
     845                 :            :                                         f_.write(junk, preludeSize);
     846                 :            :                                         delete [] junk;
     847                 :            : 
     848                 :            :                                         // the first chunk begins at the end of prelude
     849                 :            :                                 }
     850                 :            : 
     851                 :            :                                 void writePoint(const char *p) {
     852                 :            :                                         if (chunk_state_.points_in_chunk == chunk_size_ ||
     853                 :            :                                                         !pcompressor_ || !pencoder_) {
     854                 :            :                                                 // Time to (re)init the encoder
     855                 :            :                                                 //
     856                 :            :                                                 pcompressor_.reset();
     857                 :            :                                                 if (pencoder_) {
     858                 :            :                                                         pencoder_->done(); // make sure we flush it out
     859                 :            :                                                         pencoder_.reset();
     860                 :            :                                                 }
     861                 :            : 
     862                 :            :                                                 // reset chunk state
     863                 :            :                                                 //
     864                 :            :                                                 chunk_state_.current_chunk_index ++;
     865                 :            :                                                 chunk_state_.points_in_chunk = 0;
     866                 :            : 
     867                 :            :                                                 // take note of the current offset
     868                 :            :                                                 std::streamsize offset = f_.tellp();
     869                 :            :                                                 if (chunk_state_.current_chunk_index > 0) {
     870                 :            :                                                         // When we hit this point the first time around, we don't do anything since we are just
     871                 :            :                                                         // starting to write out our first chunk.
     872                 :            :                                                         chunk_sizes_.push_back(offset - chunk_state_.last_chunk_write_offset);
     873                 :            :                                                 }
     874                 :            : 
     875                 :            :                                                 chunk_state_.last_chunk_write_offset = offset;
     876                 :            : 
     877                 :            :                                                 // reinit stuff
     878                 :            :                                                 pencoder_.reset(new encoders::arithmetic<__ofstream_wrapper<std::ofstream> >(wrapper_));
     879                 :            :                                                 pcompressor_ = factory::build_compressor(*pencoder_, schema_);
     880                 :            :                                         }
     881                 :            : 
     882                 :            :                                         // now write the point
     883                 :            :                                         pcompressor_->compress(p);
     884                 :            :                                         chunk_state_.total_written ++;
     885                 :            :                                         chunk_state_.points_in_chunk ++;
     886                 :            : 
     887                 :            : 
     888                 :            :                                         _update_min_max(*(reinterpret_cast<const formats::las::point10*>(p)));
     889                 :            :                                 }
     890                 :            : 
     891                 :            :                                 void close() {
     892                 :            :                                         _flush();
     893                 :            : 
     894                 :            :                                         if (f_.is_open())
     895                 :            :                                                 f_.close();
     896                 :            :                                 }
     897                 :            : 
     898                 :            :                         private:
     899                 :            :                                 void _update_min_max(const formats::las::point10& p) {
     900                 :            :                                         double x = p.x * header_.scale.x + header_.offset.x,
     901                 :            :                                                    y = p.y * header_.scale.y + header_.offset.y,
     902                 :            :                                                    z = p.z * header_.scale.z + header_.offset.z;
     903                 :            : 
     904                 :            :                                         header_.minimum.x = (std::min)(x, header_.minimum.x);
     905                 :            :                                         header_.minimum.y = (std::min)(y, header_.minimum.y);
     906                 :            :                                         header_.minimum.z = (std::min)(z, header_.minimum.z);
     907                 :            : 
     908                 :            :                                         header_.maximum.x = (std::max)(x, header_.maximum.x);
     909                 :            :                                         header_.maximum.y = (std::max)(y, header_.maximum.y);
     910                 :            :                                         header_.maximum.z = (std::max)(z, header_.maximum.z);
     911                 :            :                                 }
     912                 :            : 
     913                 :            :                                 void _flush() {
     914                 :            :                                         // flush out the encoder
     915                 :            :                                         pencoder_->done();
     916                 :            : 
     917                 :            :                                         // Note down the size of the offset of this last chunk
     918                 :            :                                         chunk_sizes_.push_back((std::streamsize)f_.tellp() - chunk_state_.last_chunk_write_offset);
     919                 :            : 
     920                 :            :                                         // Time to write our header
     921                 :            :                                         // Fill up things not filled up by our header
     922                 :            :                                         //
     923                 :            :                                         header_.magic[0] = 'L'; header_.magic[1] = 'A';
     924                 :            :                                         header_.magic[2] = 'S'; header_.magic[3] = 'F';
     925                 :            : 
     926                 :            :                                         header_.version.major = 1;
     927                 :            :                                         header_.version.minor = 2;
     928                 :            : 
     929                 :            :                                         header_.header_size = sizeof(header_);
     930                 :            :                                         header_.point_offset = sizeof(header) + 54 + (34 + static_cast<unsigned int>(schema_.records.size()) * 6); // 54 is the size of one vlr header
     931                 :            :                                         header_.vlr_count = 1;
     932                 :            : 
     933                 :            :                                         header_.point_format_id = schema_.format();
     934                 :            :                                         header_.point_format_id |= (1 << 7);
     935                 :            :                                         header_.point_record_length = static_cast<unsigned short>(schema_.size_in_bytes());
     936                 :            :                                         header_.point_count = static_cast<unsigned int>(chunk_state_.total_written);
     937                 :            : 
     938                 :            :                                         // make sure we re-arrange mins and maxs for writing
     939                 :            :                                         //
     940                 :            :                                         double mx, my, mz, nx, ny, nz;
     941                 :            :                                         nx = header_.minimum.x; mx = header_.maximum.x;
     942                 :            :                                         ny = header_.minimum.y; my = header_.maximum.y;
     943                 :            :                                         nz = header_.minimum.z; mz = header_.maximum.z;
     944                 :            : 
     945                 :            :                                         header_.minimum.x = mx; header_.minimum.y = nx;
     946                 :            :                                         header_.minimum.z = my; header_.maximum.x = ny;
     947                 :            :                                         header_.maximum.y = mz; header_.maximum.z = nz;
     948                 :            : 
     949                 :            :                                         f_.seekp(0);
     950                 :            :                                         f_.write(reinterpret_cast<char*>(&header_), sizeof(header_));
     951                 :            : 
     952                 :            :                                         // before we can write the VLR, we need to write the LAS VLR definition
     953                 :            :                                         // for it
     954                 :            :                                         //
     955                 :            : #pragma pack(push, 1)
     956                 :            :                                         struct {
     957                 :            :                                                 unsigned short reserved;
     958                 :            :                                                 char user_id[16];
     959                 :            :                                                 unsigned short record_id;
     960                 :            :                                                 unsigned short record_length_after_header;
     961                 :            :                                                 char description[32];
     962                 :            :                                         } las_vlr_header;
     963                 :            : #pragma pack(pop)
     964                 :            : 
     965                 :            :                                         las_vlr_header.reserved = 0;
     966                 :            :                                         las_vlr_header.record_id = 22204;
     967                 :            :                                         las_vlr_header.record_length_after_header = static_cast<unsigned short>(34 + (schema_.records.size() * 6));
     968                 :            : 
     969                 :            :                                         strcpy(las_vlr_header.user_id, "laszip encoded");
     970                 :            :                                         strcpy(las_vlr_header.description, "laz-perf variant");
     971                 :            : 
     972                 :            :                                         // write the las vlr header
     973                 :            :                                         f_.write(reinterpret_cast<char*>(&las_vlr_header), sizeof(las_vlr_header));
     974                 :            : 
     975                 :            : 
     976                 :            :                                         // prep our VLR so we can write it
     977                 :            :                                         //
     978                 :            :                                         laz_vlr vlr = laz_vlr::from_schema(schema_, chunk_size_);
     979                 :            : 
     980                 :            :                     std::unique_ptr<char> vlrbuf(new char[vlr.size()]);
     981                 :            :                     vlr.extract(vlrbuf.get());
     982                 :            :                     f_.write(vlrbuf.get(), vlr.size());
     983                 :            : 
     984                 :            :                                         // TODO: Write chunk table
     985                 :            :                                         //
     986                 :            :                                         _writeChunks();
     987                 :            :                                 }
     988                 :            : 
     989                 :            :                                 void _writeChunks() {
     990                 :            :                                         // move to the end of the file to start emitting our compresed table
     991                 :            :                                         f_.seekp(0, std::ios::end);
     992                 :            : 
     993                 :            :                                         // take note of where we're writing the chunk table, we need this later
     994                 :            :                                         int64_t chunk_table_offset = static_cast<int64_t>(f_.tellp());
     995                 :            : 
     996                 :            :                                         // write out the chunk table header (version and total chunks)
     997                 :            : #pragma pack(push, 1)
     998                 :            :                                         struct {
     999                 :            :                                                 unsigned int version,
    1000                 :            :                                                                          chunks_count;
    1001                 :            :                                         } chunk_table_header = { 0, static_cast<unsigned int>(chunk_sizes_.size()) };
    1002                 :            : #pragma pack(pop)
    1003                 :            : 
    1004                 :            :                                         f_.write(reinterpret_cast<char*>(&chunk_table_header),
    1005                 :            :                                                          sizeof(chunk_table_header));
    1006                 :            : 
    1007                 :            : 
    1008                 :            :                                         // Now compress and write the chunk table
    1009                 :            :                                         //
    1010                 :            :                                         __ofstream_wrapper<std::ofstream> w(f_);
    1011                 :            : 
    1012                 :            :                                         encoders::arithmetic<__ofstream_wrapper<std::ofstream> > encoder(w);
    1013                 :            :                                         compressors::integer comp(32, 2);
    1014                 :            : 
    1015                 :            :                                         comp.init();
    1016                 :            : 
    1017                 :            :                                         for (size_t i = 0 ; i < chunk_sizes_.size() ; i ++) {
    1018                 :            :                                                 comp.compress(encoder,
    1019                 :            :                                                                 i ? static_cast<int>(chunk_sizes_[i-1]) : 0,
    1020                 :            :                                                                 static_cast<int>(chunk_sizes_[i]), 1);
    1021                 :            :                                         }
    1022                 :            : 
    1023                 :            :                                         encoder.done();
    1024                 :            : 
    1025                 :            :                                         // go back to where we're supposed to write chunk table offset
    1026                 :            :                                         f_.seekp(header_.point_offset);
    1027                 :            :                                         f_.write(reinterpret_cast<char*>(&chunk_table_offset), sizeof(chunk_table_offset));
    1028                 :            :                                 }
    1029                 :            : 
    1030                 :            :                                 std::ofstream f_;
    1031                 :            :                                 __ofstream_wrapper<std::ofstream> wrapper_;
    1032                 :            : 
    1033                 :            :                                 formats::dynamic_compressor::ptr pcompressor_;
    1034                 :            :                                 std::shared_ptr<encoders::arithmetic<__ofstream_wrapper<std::ofstream> > > pencoder_;
    1035                 :            : 
    1036                 :            :                                 factory::record_schema schema_;
    1037                 :            : 
    1038                 :            :                                 header header_;
    1039                 :            :                                 unsigned int chunk_size_;
    1040                 :            : 
    1041                 :            :                                 struct __chunk_state {
    1042                 :            :                                         int64_t total_written; // total points written
    1043                 :            :                                         int64_t current_chunk_index; //  the current chunk index we're compressing
    1044                 :            :                                         unsigned int points_in_chunk;
    1045                 :            :                                         std::streamsize last_chunk_write_offset;
    1046                 :            :                                         __chunk_state() : total_written(0), current_chunk_index(-1), points_in_chunk(0), last_chunk_write_offset(0) {}
    1047                 :            :                                 } chunk_state_;
    1048                 :            : 
    1049                 :            :                                 std::vector<int64_t> chunk_sizes_; // all the places where chunks begin
    1050                 :            :                         };
    1051                 :            :                 }
    1052                 :            :         }
    1053                 :            : }
    1054                 :            : 
    1055                 :            : #endif // __io_hpp__

Generated by: LCOV version 1.14