1 /*
2 ===============================================================================
3 
4   FILE:  laszip_dll.cpp
5 
6   CONTENTS:
7 
8     see corresponding header file
9 
10   PROGRAMMERS:
11 
12     martin.isenburg@rapidlasso.com  -  http://rapidlasso.com
13 
14   COPYRIGHT:
15 
16     (c) 2007-2019, martin isenburg, rapidlasso - fast tools to catch reality
17 
18     This is free software; you can redistribute and/or modify it under the
19     terms of the GNU Lesser General Licence as published by the Free Software
20     Foundation. See the COPYING file for more information.
21 
22     This software is distributed WITHOUT ANY WARRANTY and without even the
23     implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
24 
25   CHANGE HISTORY:
26 
27     15 October 2019 -- support reading from and writing to unicode file names under Windows
28     20 March 2019 -- check consistent legacy and extended classification in laszip_write_point()
29      7 November 2018 -- assure identical legacy and extended flags in laszip_write_point()
30     20 October 2018 -- changed (U8*) to (const U8*) for all out->put___() calls
31      5 October 2018 -- corrected 'is_empty' return value in laszip_inside_rectangle()
32     29 September 2018 -- laszip_prepare_point_for_write() sets extended_point_type
33     19 September 2018 -- removed tuples and triple support from attributes
34      7 September 2018 -- replaced calls to _strdup with calls to the LASCopyString macro
35      6 April 2018 -- added zero() function to laszip_dll struct to fix memory leak
36     30 August 2017 -- completing stream-based writing (with writing LAS header)
37     23 August 2017 -- turn on "native" by default
38      3 August 2017 -- new 'laszip_create_laszip_vlr()' gets VLR as C++ std::vector
39     29 July 2017 -- integrating minimal stream-based reading/writing into branch
40     20 July 2017 -- Andrew Bell adds support for stream-based reading/writing
41     28 May 2017 -- support for "LAS 1.4 selective decompression" added into DLL API
42     25 April 2017 -- adding initial support for new "native LAS 1.4 extension"
43      8 January 2017 -- changed from "laszip_dll.h" to "laszip_api.h" for hobu
44 
45 ===============================================================================
46 */
47 
48 #define LASZIP_DYN_LINK
49 #define LASZIP_SOURCE
50 
51 #include <laszip/laszip_api.h>
52 #include <stdio.h>
53 #include <string.h>
54 #include <stdlib.h>
55 #include <vector>
56 
57 #include "laszip.hpp"
58 #include "lasattributer.hpp"
59 #include "bytestreamout_file.hpp"
60 #include "bytestreamin_file.hpp"
61 #include "bytestreamout_array.hpp"
62 #include "bytestreamin_array.hpp"
63 #include "bytestreamin_istream.hpp"
64 #include "bytestreamout_ostream.hpp"
65 #include "laswritepoint.hpp"
66 #include "lasreadpoint.hpp"
67 #include "lasquadtree.hpp"
68 #include "lasindex.hpp"
69 
70 class laszip_dll_inventory
71 {
72 public:
active() const73   BOOL active() const { return (first == FALSE); };
74   U32 number_of_point_records;
75   U32 number_of_points_by_return[16];
76   I32 max_X;
77   I32 min_X;
78   I32 max_Y;
79   I32 min_Y;
80   I32 max_Z;
81   I32 min_Z;
add(const laszip_point_struct * point)82   void add(const laszip_point_struct* point)
83   {
84     number_of_point_records++;
85     if (point->extended_point_type)
86     {
87       number_of_points_by_return[point->extended_return_number]++;
88     }
89     else
90     {
91       number_of_points_by_return[point->return_number]++;
92     }
93     if (first)
94     {
95       min_X = max_X = point->X;
96       min_Y = max_Y = point->Y;
97       min_Z = max_Z = point->Z;
98       first = FALSE;
99     }
100     else
101     {
102       if (point->X < min_X) min_X = point->X;
103       else if (point->X > max_X) max_X = point->X;
104       if (point->Y < min_Y) min_Y = point->Y;
105       else if (point->Y > max_Y) max_Y = point->Y;
106       if (point->Z < min_Z) min_Z = point->Z;
107       else if (point->Z > max_Z) max_Z = point->Z;
108     }
109   }
laszip_dll_inventory()110   laszip_dll_inventory()
111   {
112     U32 i;
113     number_of_point_records = 0;
114     for (i = 0; i < 16; i++) number_of_points_by_return[i] = 0;
115     max_X = min_X = 0;
116     max_Y = min_Y = 0;
117     max_Z = min_Z = 0;
118     first = TRUE;
119   }
120 private:
121   BOOL first;
122 };
123 
124 typedef struct laszip_dll {
125   laszip_header_struct header;
126   I64 p_count;
127   I64 npoints;
128   laszip_point_struct point;
129   U8** point_items;
130   FILE* file;
131   ByteStreamIn* streamin;
132   LASreadPoint* reader;
133   ByteStreamOut* streamout;
134   LASwritePoint* writer;
135   LASattributer* attributer;
136   CHAR error[1024];
137   CHAR warning[1024];
138   LASindex* lax_index;
139   F64 lax_r_min_x;
140   F64 lax_r_min_y;
141   F64 lax_r_max_x;
142   F64 lax_r_max_y;
143   CHAR* lax_file_name;
144   BOOL lax_create;
145   BOOL lax_append;
146   BOOL lax_exploit;
147   U32 las14_decompress_selective;
148   BOOL preserve_generating_software;
149   BOOL request_native_extension;
150   BOOL request_compatibility_mode;
151   BOOL compatibility_mode;
152   U32 set_chunk_size;
153   I32 start_scan_angle;
154   I32 start_extended_returns;
155   I32 start_classification;
156   I32 start_flags_and_channel;
157   I32 start_NIR_band;
158   laszip_dll_inventory* inventory;
159   std::vector<void *> buffers;
160 
zerolaszip_dll161   void zero()
162   {
163     memset(&header, 0, sizeof(laszip_header_struct));
164     p_count = 0;
165     npoints = 0;
166     memset(&point, 0, sizeof(laszip_point_struct));
167     point_items = NULL;
168     file = NULL;
169     streamin = NULL;
170     reader = NULL;
171     streamout = NULL;
172     writer = NULL;
173     attributer = NULL;
174     memset(error, 0, 1024);
175     memset(warning, 0, 1024);
176     lax_index = NULL;
177     lax_r_min_x = 0.0;
178     lax_r_min_y = 0.0;
179     lax_r_max_x = 0.0;
180     lax_r_max_y = 0.0;
181     lax_file_name = NULL;
182     lax_create = FALSE;
183     lax_append = FALSE;
184     lax_exploit = FALSE;
185     las14_decompress_selective = 0;
186     preserve_generating_software = FALSE;
187     request_native_extension = FALSE;
188     request_compatibility_mode = FALSE;
189     compatibility_mode = FALSE;
190     set_chunk_size = 0;
191     start_scan_angle = 0;
192     start_extended_returns = 0;
193     start_classification = 0;
194     start_flags_and_channel = 0;
195     start_NIR_band = 0;
196     inventory = NULL;
197   };
198 } laszip_dll_struct;
199 
200 /*---------------------------------------------------------------------------*/
201 LASZIP_API laszip_I32
laszip_get_version(laszip_U8 * version_major,laszip_U8 * version_minor,laszip_U16 * version_revision,laszip_U32 * version_build)202 laszip_get_version(
203     laszip_U8*                         version_major
204     , laszip_U8*                       version_minor
205     , laszip_U16*                      version_revision
206     , laszip_U32*                      version_build
207 )
208 {
209   try
210   {
211     *version_major = LASZIP_VERSION_MAJOR;
212     *version_minor = LASZIP_VERSION_MINOR;
213     *version_revision = LASZIP_VERSION_REVISION;
214     *version_build = LASZIP_VERSION_BUILD_DATE;
215   }
216   catch (...)
217   {
218     return 1;
219   }
220 
221   return 0;
222 }
223 
224 /*---------------------------------------------------------------------------*/
225 LASZIP_API laszip_I32
laszip_get_error(laszip_POINTER pointer,laszip_CHAR ** error)226 laszip_get_error(
227     laszip_POINTER                     pointer
228     , laszip_CHAR**                    error
229 )
230 {
231   if (pointer == 0) return 1;
232   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
233 
234   try
235   {
236     *error = laszip_dll->error;
237   }
238   catch (...)
239   {
240     sprintf(laszip_dll->error, "internal error in laszip_get_error");
241     return 1;
242   }
243 
244   return 0;
245 }
246 
247 /*---------------------------------------------------------------------------*/
248 LASZIP_API laszip_I32
laszip_get_warning(laszip_POINTER pointer,laszip_CHAR ** warning)249 laszip_get_warning(
250     laszip_POINTER                     pointer
251     , laszip_CHAR**                    warning
252 )
253 {
254   if (pointer == 0) return 1;
255   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
256 
257   try
258   {
259     *warning = laszip_dll->warning;
260   }
261   catch (...)
262   {
263     sprintf(laszip_dll->error, "internal error in laszip_get_warning");
264     return 1;
265   }
266 
267   return 0;
268 }
269 
270 /*---------------------------------------------------------------------------*/
271 LASZIP_API laszip_I32
laszip_create(laszip_POINTER * pointer)272 laszip_create(
273     laszip_POINTER*                    pointer
274 )
275 {
276   if (pointer == 0) return 1;
277 
278   try
279   {
280     laszip_dll_struct* laszip_dll = new laszip_dll_struct;
281     if (laszip_dll == 0)
282     {
283       return 1;
284     }
285 
286     // zero every field of the laszip_dll struct
287 
288     laszip_dll->zero();
289 
290     // create the default
291 
292     laszip_clean(laszip_dll);
293 
294     *pointer = laszip_dll;
295   }
296   catch (...)
297   {
298     return 1;
299   }
300 
301   return 0;
302 }
303 
304 /*---------------------------------------------------------------------------*/
305 LASZIP_API laszip_I32
laszip_clean(laszip_POINTER pointer)306 laszip_clean(
307     laszip_POINTER                     pointer
308 )
309 {
310   if (pointer == 0) return 1;
311   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
312 
313   try
314   {
315     if (laszip_dll->reader)
316     {
317       sprintf(laszip_dll->error, "cannot clean while reader is open.");
318       return 1;
319     }
320 
321     if (laszip_dll->writer)
322     {
323       sprintf(laszip_dll->error, "cannot clean while writer is open.");
324       return 1;
325     }
326 
327     // dealloc everything alloc in the header
328 
329     if (laszip_dll->header.user_data_in_header)
330     {
331       delete [] laszip_dll->header.user_data_in_header;
332       laszip_dll->header.user_data_in_header = 0;
333     }
334 
335     if (laszip_dll->header.vlrs)
336     {
337       U32 i;
338       for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
339       {
340         if (laszip_dll->header.vlrs[i].data)
341         {
342           delete [] laszip_dll->header.vlrs[i].data;
343         }
344       }
345       free(laszip_dll->header.vlrs);
346       laszip_dll->header.vlrs = 0;
347     }
348 
349     if (laszip_dll->header.user_data_after_header)
350     {
351       delete [] laszip_dll->header.user_data_after_header;
352       laszip_dll->header.user_data_after_header = 0;
353     }
354 
355     // dealloc everything alloc in the point
356 
357     if (laszip_dll->point.extra_bytes)
358     {
359       delete [] laszip_dll->point.extra_bytes;
360       laszip_dll->point.extra_bytes = 0;
361     }
362 
363     // dealloc point items although close_reader() / close_writer() call should have done this already
364 
365     if (laszip_dll->point_items)
366     {
367       delete [] laszip_dll->point_items;
368       laszip_dll->point_items = 0;
369     }
370 
371     // close file although close_reader() / close_writer() call should have done this already
372 
373     if (laszip_dll->file)
374     {
375       fclose(laszip_dll->file);
376       laszip_dll->file = 0;
377     }
378 
379     // dealloc streamin although close_reader() call should have done this already
380 
381     if (laszip_dll->streamin)
382     {
383       delete laszip_dll->streamin;
384       laszip_dll->streamin = 0;
385     }
386 
387     // dealloc streamout although close_writer() call should have done this already
388 
389     if (laszip_dll->streamout)
390     {
391       delete laszip_dll->streamout;
392       laszip_dll->streamout = 0;
393     }
394 
395     // dealloc the attributer
396 
397     if (laszip_dll->attributer)
398     {
399       delete laszip_dll->attributer;
400       laszip_dll->attributer = 0;
401     }
402 
403     // dealloc lax_index although close_reader() / close_writer() call should have done this already
404 
405     if (laszip_dll->lax_index)
406     {
407       delete laszip_dll->lax_index;
408       laszip_dll->lax_index = 0;
409     }
410 
411     // dealloc lax_file_name although close_writer() call should have done this already
412 
413     if (laszip_dll->lax_file_name)
414     {
415       free(laszip_dll->lax_file_name);
416       laszip_dll->lax_file_name = 0;
417     }
418 
419     // dealloc the inventory although close_writer() call should have done this already
420 
421     if (laszip_dll->inventory == 0)
422     {
423       delete laszip_dll->inventory;
424       laszip_dll->inventory = 0;
425     }
426 
427     // dealloc any data fields that were kept around in memory for others
428 
429     if (laszip_dll->buffers.size())
430     {
431       for (size_t i = 0; i < laszip_dll->buffers.size(); i++)
432       {
433         free(laszip_dll->buffers[i]);
434       }
435       laszip_dll->buffers.clear();
436     }
437 
438     // zero every field of the laszip_dll struct
439 
440     laszip_dll->zero();
441 
442     // create default header
443 
444     sprintf(laszip_dll->header.generating_software, "LASzip DLL %d.%d r%d (%d)", LASZIP_VERSION_MAJOR, LASZIP_VERSION_MINOR, LASZIP_VERSION_REVISION, LASZIP_VERSION_BUILD_DATE);
445     laszip_dll->header.version_major = 1;
446     laszip_dll->header.version_minor = 2;
447     laszip_dll->header.header_size = 227;
448     laszip_dll->header.offset_to_point_data = 227;
449     laszip_dll->header.point_data_format = 1;
450     laszip_dll->header.point_data_record_length = 28;
451     laszip_dll->header.x_scale_factor = 0.01;
452     laszip_dll->header.y_scale_factor = 0.01;
453     laszip_dll->header.z_scale_factor = 0.01;
454     laszip_dll->set_chunk_size = LASZIP_CHUNK_SIZE_DEFAULT;
455     laszip_dll->request_native_extension = TRUE;
456     laszip_dll->las14_decompress_selective = LASZIP_DECOMPRESS_SELECTIVE_ALL;
457   }
458   catch (...)
459   {
460     sprintf(laszip_dll->error, "internal error in laszip_clean");
461     return 1;
462   }
463 
464   return 0;
465 }
466 
467 /*---------------------------------------------------------------------------*/
468 LASZIP_API laszip_I32
laszip_destroy(laszip_POINTER pointer)469 laszip_destroy(
470     laszip_POINTER                     pointer
471 )
472 {
473   if (pointer == 0) return 1;
474   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
475 
476   int err = 0;
477 
478   try
479   {
480     err = laszip_clean(laszip_dll);
481     delete laszip_dll;
482   }
483   catch (...)
484   {
485     return 1;
486   }
487 
488   return err;
489 }
490 
491 /*---------------------------------------------------------------------------*/
492 LASZIP_API laszip_I32
laszip_get_header_pointer(laszip_POINTER pointer,laszip_header_struct ** header_pointer)493 laszip_get_header_pointer(
494     laszip_POINTER                     pointer
495     , laszip_header_struct**           header_pointer
496 )
497 {
498   if (pointer == 0) return 1;
499   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
500 
501   try
502   {
503     if (header_pointer == 0)
504     {
505       sprintf(laszip_dll->error, "laszip_header_struct pointer 'header_pointer' is zero");
506       return 1;
507     }
508 
509     *header_pointer = &laszip_dll->header;
510   }
511   catch (...)
512   {
513     sprintf(laszip_dll->error, "internal error in laszip_get_header_pointer");
514     return 1;
515   }
516 
517   laszip_dll->error[0] = '\0';
518   return 0;
519 }
520 
521 /*---------------------------------------------------------------------------*/
522 LASZIP_API laszip_I32
laszip_get_point_pointer(laszip_POINTER pointer,laszip_point_struct ** point_pointer)523 laszip_get_point_pointer(
524     laszip_POINTER                     pointer
525     , laszip_point_struct**            point_pointer
526 )
527 {
528   if (pointer == 0) return 1;
529   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
530 
531   try
532   {
533     if (point_pointer == 0)
534     {
535       sprintf(laszip_dll->error, "laszip_point_struct pointer 'point_pointer' is zero");
536       return 1;
537     }
538 
539     *point_pointer = &laszip_dll->point;
540   }
541   catch (...)
542   {
543     sprintf(laszip_dll->error, "internal error in laszip_get_point_pointer");
544     return 1;
545   }
546 
547   laszip_dll->error[0] = '\0';
548   return 0;
549 }
550 
551 /*---------------------------------------------------------------------------*/
552 LASZIP_API laszip_I32
laszip_get_point_count(laszip_POINTER pointer,laszip_I64 * count)553 laszip_get_point_count(
554     laszip_POINTER                     pointer
555     , laszip_I64*                      count
556 )
557 {
558   if (pointer == 0) return 1;
559   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
560 
561   try
562   {
563     if (count == 0)
564     {
565       sprintf(laszip_dll->error, "laszip_I64 pointer 'count' is zero");
566       return 1;
567     }
568 
569     if ((laszip_dll->reader == 0) && (laszip_dll->writer == 0))
570     {
571       sprintf(laszip_dll->error, "getting count before reader or writer was opened");
572       return 1;
573     }
574 
575     *count = laszip_dll->p_count;
576   }
577   catch (...)
578   {
579     sprintf(laszip_dll->error, "internal error in laszip_get_point_count");
580     return 1;
581   }
582 
583   laszip_dll->error[0] = '\0';
584   return 0;
585 }
586 
587 /*---------------------------------------------------------------------------*/
588 LASZIP_API laszip_I32
laszip_set_header(laszip_POINTER pointer,const laszip_header_struct * header)589 laszip_set_header(
590     laszip_POINTER                     pointer
591     , const laszip_header_struct*      header
592 )
593 {
594   if (pointer == 0) return 1;
595   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
596 
597   try
598   {
599     if (header == 0)
600     {
601       sprintf(laszip_dll->error, "laszip_header_struct pointer 'header' is zero");
602       return 1;
603     }
604 
605     if (laszip_dll->reader)
606     {
607       sprintf(laszip_dll->error, "cannot set header after reader was opened");
608       return 1;
609     }
610 
611     if (laszip_dll->writer)
612     {
613       sprintf(laszip_dll->error, "cannot set header after writer was opened");
614       return 1;
615     }
616 
617     // dealloc the attributer (if needed)
618 
619     if (laszip_dll->attributer)
620     {
621       delete laszip_dll->attributer;
622       laszip_dll->attributer = 0;
623     }
624 
625     // populate the header
626 
627     U32 i;
628 
629     laszip_dll->header.file_source_ID = header->file_source_ID;
630     laszip_dll->header.global_encoding = header->global_encoding;
631     laszip_dll->header.project_ID_GUID_data_1 = header->project_ID_GUID_data_1;
632     laszip_dll->header.project_ID_GUID_data_2 = header->project_ID_GUID_data_2;
633     laszip_dll->header.project_ID_GUID_data_3 = header->project_ID_GUID_data_3;
634     memcpy(laszip_dll->header.project_ID_GUID_data_4, header->project_ID_GUID_data_4, 8);
635     laszip_dll->header.version_major = header->version_major;
636     laszip_dll->header.version_minor = header->version_minor;
637     memcpy(laszip_dll->header.system_identifier, header->system_identifier, 32);
638     memcpy(laszip_dll->header.generating_software, header->generating_software, 32);
639     laszip_dll->header.file_creation_day = header->file_creation_day;
640     laszip_dll->header.file_creation_year = header->file_creation_year;
641     laszip_dll->header.header_size = header->header_size;
642     laszip_dll->header.offset_to_point_data = header->offset_to_point_data;
643     laszip_dll->header.number_of_variable_length_records = header->number_of_variable_length_records;
644     laszip_dll->header.point_data_format = header->point_data_format;
645     laszip_dll->header.point_data_record_length = header->point_data_record_length;
646     laszip_dll->header.number_of_point_records = header->number_of_point_records;
647     for (i = 0; i < 5; i++) laszip_dll->header.number_of_points_by_return[i] = header->number_of_points_by_return[i];
648     laszip_dll->header.x_scale_factor = header->x_scale_factor;
649     laszip_dll->header.y_scale_factor = header->y_scale_factor;
650     laszip_dll->header.z_scale_factor = header->z_scale_factor;
651     laszip_dll->header.x_offset = header->x_offset;
652     laszip_dll->header.y_offset = header->y_offset;
653     laszip_dll->header.z_offset = header->z_offset;
654     laszip_dll->header.max_x = header->max_x;
655     laszip_dll->header.min_x = header->min_x;
656     laszip_dll->header.max_y = header->max_y;
657     laszip_dll->header.min_y = header->min_y;
658     laszip_dll->header.max_z = header->max_z;
659     laszip_dll->header.min_z = header->min_z;
660 
661     if (laszip_dll->header.version_minor >= 3)
662     {
663       laszip_dll->header.start_of_waveform_data_packet_record = header->start_of_first_extended_variable_length_record;
664     }
665 
666     if (laszip_dll->header.version_minor >= 4)
667     {
668       laszip_dll->header.start_of_first_extended_variable_length_record = header->start_of_first_extended_variable_length_record;
669       laszip_dll->header.number_of_extended_variable_length_records = header->number_of_extended_variable_length_records;
670       laszip_dll->header.extended_number_of_point_records = header->extended_number_of_point_records;
671       for (i = 0; i < 15; i++) laszip_dll->header.extended_number_of_points_by_return[i] = header->extended_number_of_points_by_return[i];
672     }
673 
674     laszip_dll->header.user_data_in_header_size = header->user_data_in_header_size;
675     if (laszip_dll->header.user_data_in_header)
676     {
677       delete [] laszip_dll->header.user_data_in_header;
678       laszip_dll->header.user_data_in_header = 0;
679     }
680     if (header->user_data_in_header_size)
681     {
682       if (header->user_data_in_header == 0)
683       {
684         sprintf(laszip_dll->error, "header->user_data_in_header_size is %d but header->user_data_in_header is NULL", header->user_data_in_header_size);
685         return 1;
686       }
687       laszip_dll->header.user_data_in_header = new U8[header->user_data_in_header_size];
688       memcpy(laszip_dll->header.user_data_in_header, header->user_data_in_header, header->user_data_in_header_size);
689     }
690 
691     if (laszip_dll->header.vlrs)
692     {
693       for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
694       {
695         if (laszip_dll->header.vlrs[i].data)
696         {
697           delete [] laszip_dll->header.vlrs[i].data;
698         }
699       }
700       free(laszip_dll->header.vlrs);
701       laszip_dll->header.vlrs = 0;
702     }
703     if (header->number_of_variable_length_records)
704     {
705       laszip_dll->header.vlrs = (laszip_vlr*)malloc(sizeof(laszip_vlr)*header->number_of_variable_length_records);
706       for (i = 0; i < header->number_of_variable_length_records; i++)
707       {
708         laszip_dll->header.vlrs[i].reserved = header->vlrs[i].reserved;
709         memcpy(laszip_dll->header.vlrs[i].user_id, header->vlrs[i].user_id, 16);
710         laszip_dll->header.vlrs[i].record_id = header->vlrs[i].record_id;
711         laszip_dll->header.vlrs[i].record_length_after_header = header->vlrs[i].record_length_after_header;
712         memcpy(laszip_dll->header.vlrs[i].description, header->vlrs[i].description, 32);
713         if (header->vlrs[i].record_length_after_header)
714         {
715           if (header->vlrs[i].data == 0)
716           {
717             sprintf(laszip_dll->error, "header->vlrs[%d].record_length_after_header is %d but header->vlrs[%d].data is NULL", i, header->vlrs[i].record_length_after_header, i);
718             return 1;
719           }
720           laszip_dll->header.vlrs[i].data = new U8[header->vlrs[i].record_length_after_header];
721           memcpy(laszip_dll->header.vlrs[i].data, header->vlrs[i].data, header->vlrs[i].record_length_after_header);
722         }
723         else
724         {
725           laszip_dll->header.vlrs[i].data = 0;
726         }
727 
728         // populate the attributer if needed
729 
730         if ((strcmp(laszip_dll->header.vlrs[i].user_id, "LASF_Spec") == 0) && (laszip_dll->header.vlrs[i].record_id == 4))
731         {
732           if (laszip_dll->attributer == 0)
733           {
734             laszip_dll->attributer = new LASattributer;
735             if (laszip_dll->attributer == 0)
736             {
737               sprintf(laszip_dll->error, "cannot allocate LASattributer");
738               return 1;
739             }
740           }
741           laszip_dll->attributer->init_attributes(laszip_dll->header.vlrs[i].record_length_after_header/sizeof(LASattribute), (LASattribute*)laszip_dll->header.vlrs[i].data);
742         }
743       }
744     }
745 
746     laszip_dll->header.user_data_after_header_size = header->user_data_after_header_size;
747     if (laszip_dll->header.user_data_after_header)
748     {
749       delete [] laszip_dll->header.user_data_after_header;
750       laszip_dll->header.user_data_after_header = 0;
751     }
752     if (header->user_data_after_header_size)
753     {
754       if (header->user_data_after_header == 0)
755       {
756         sprintf(laszip_dll->error, "header->user_data_after_header_size is %d but header->user_data_after_header is NULL", header->user_data_after_header_size);
757         return 1;
758       }
759       laszip_dll->header.user_data_after_header = new U8[header->user_data_after_header_size];
760       memcpy(laszip_dll->header.user_data_after_header, header->user_data_after_header, header->user_data_after_header_size);
761     }
762   }
763   catch (...)
764   {
765     sprintf(laszip_dll->error, "internal error in laszip_set_header");
766     return 1;
767   }
768 
769   laszip_dll->error[0] = '\0';
770   return 0;
771 }
772 
773 /*---------------------------------------------------------------------------*/
774 LASZIP_API laszip_I32
laszip_set_point_type_and_size(laszip_POINTER pointer,laszip_U8 point_type,laszip_U16 point_size)775 laszip_set_point_type_and_size(
776     laszip_POINTER                     pointer
777     , laszip_U8                        point_type
778     , laszip_U16                       point_size
779 )
780 {
781   if (pointer == 0) return 1;
782   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
783 
784   try
785   {
786     if (laszip_dll->reader)
787     {
788       sprintf(laszip_dll->error, "cannot set point format and point size after reader was opened");
789       return 1;
790     }
791 
792     if (laszip_dll->writer)
793     {
794       sprintf(laszip_dll->error, "cannot set point format and point size after writer was opened");
795       return 1;
796     }
797 
798     // check if point type and type are supported
799 
800     if (!LASzip().setup(point_type, point_size, LASZIP_COMPRESSOR_NONE))
801     {
802       sprintf(laszip_dll->error, "invalid combination of point_type %d and point_size %d", (I32)point_type, (I32)point_size);
803       return 1;
804     }
805 
806     // set point type and point size
807 
808     laszip_dll->header.point_data_format = point_type;
809     laszip_dll->header.point_data_record_length = point_size;
810   }
811   catch (...)
812   {
813     sprintf(laszip_dll->error, "internal error in laszip_set_point_type_and_size");
814     return 1;
815   }
816 
817   laszip_dll->error[0] = '\0';
818   return 0;
819 }
820 
821 /*---------------------------------------------------------------------------*/
822 LASZIP_API laszip_I32
laszip_check_for_integer_overflow(laszip_POINTER pointer)823 laszip_check_for_integer_overflow(
824     laszip_POINTER                     pointer
825 )
826 {
827   if (pointer == 0) return 1;
828   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
829 
830   try
831   {
832     // get a pointer to the header
833 
834     laszip_header_struct* header = &(laszip_dll->header);
835 
836     // quantize and dequantize the bounding box with current scale_factor and offset
837 
838     I32 quant_min_x = I32_QUANTIZE((header->min_x-header->x_offset)/header->x_scale_factor);
839     I32 quant_max_x = I32_QUANTIZE((header->max_x-header->x_offset)/header->x_scale_factor);
840     I32 quant_min_y = I32_QUANTIZE((header->min_y-header->y_offset)/header->y_scale_factor);
841     I32 quant_max_y = I32_QUANTIZE((header->max_y-header->y_offset)/header->y_scale_factor);
842     I32 quant_min_z = I32_QUANTIZE((header->min_z-header->z_offset)/header->z_scale_factor);
843     I32 quant_max_z = I32_QUANTIZE((header->max_z-header->z_offset)/header->z_scale_factor);
844 
845     F64 dequant_min_x = header->x_scale_factor*quant_min_x+header->x_offset;
846     F64 dequant_max_x = header->x_scale_factor*quant_max_x+header->x_offset;
847     F64 dequant_min_y = header->y_scale_factor*quant_min_y+header->y_offset;
848     F64 dequant_max_y = header->y_scale_factor*quant_max_y+header->y_offset;
849     F64 dequant_min_z = header->z_scale_factor*quant_min_z+header->z_offset;
850     F64 dequant_max_z = header->z_scale_factor*quant_max_z+header->z_offset;
851 
852     // make sure that there is not sign flip (a 32-bit integer overflow) for the bounding box
853 
854     if ((header->min_x > 0) != (dequant_min_x > 0))
855     {
856       sprintf(laszip_dll->error, "quantization sign flip for min_x from %g to %g. set scale factor for x coarser than %g\n", header->min_x, dequant_min_x, header->x_scale_factor);
857       return 1;
858     }
859     if ((header->max_x > 0) != (dequant_max_x > 0))
860     {
861       sprintf(laszip_dll->error, "quantization sign flip for max_x from %g to %g. set scale factor for x coarser than %g\n", header->max_x, dequant_max_x, header->x_scale_factor);
862       return 1;
863     }
864     if ((header->min_y > 0) != (dequant_min_y > 0))
865     {
866       sprintf(laszip_dll->error, "quantization sign flip for min_y from %g to %g. set scale factor for y coarser than %g\n", header->min_y, dequant_min_y, header->y_scale_factor);
867       return 1;
868     }
869     if ((header->max_y > 0) != (dequant_max_y > 0))
870     {
871       sprintf(laszip_dll->error, "quantization sign flip for max_y from %g to %g. set scale factor for y coarser than %g\n", header->max_y, dequant_max_y, header->y_scale_factor);
872       return 1;
873     }
874     if ((header->min_z > 0) != (dequant_min_z > 0))
875     {
876       sprintf(laszip_dll->error, "quantization sign flip for min_z from %g to %g. set scale factor for z coarser than %g\n", header->min_z, dequant_min_z, header->z_scale_factor);
877       return 1;
878     }
879     if ((header->max_z > 0) != (dequant_max_z > 0))
880     {
881       sprintf(laszip_dll->error, "quantization sign flip for max_z from %g to %g. set scale factor for z coarser than %g\n", header->max_z, dequant_max_z, header->z_scale_factor);
882       return 1;
883     }
884   }
885   catch (...)
886   {
887     sprintf(laszip_dll->error, "internal error in laszip_auto_offset");
888     return 1;
889   }
890 
891   laszip_dll->error[0] = '\0';
892   return 0;
893 }
894 
895 /*---------------------------------------------------------------------------*/
896 LASZIP_API laszip_I32
laszip_auto_offset(laszip_POINTER pointer)897 laszip_auto_offset(
898     laszip_POINTER                     pointer
899 )
900 {
901   if (pointer == 0) return 1;
902   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
903 
904   try
905   {
906     if (laszip_dll->reader)
907     {
908       sprintf(laszip_dll->error, "cannot auto offset after reader was opened");
909       return 1;
910     }
911 
912     if (laszip_dll->writer)
913     {
914       sprintf(laszip_dll->error, "cannot auto offset after writer was opened");
915       return 1;
916     }
917 
918     // get a pointer to the header
919 
920     laszip_header_struct* header = &(laszip_dll->header);
921 
922     // check scale factor
923 
924     F64 x_scale_factor = header->x_scale_factor;
925     F64 y_scale_factor = header->y_scale_factor;
926     F64 z_scale_factor = header->z_scale_factor;
927 
928     if ((x_scale_factor <= 0) || !F64_IS_FINITE(x_scale_factor))
929     {
930       sprintf(laszip_dll->error, "invalid x scale_factor %g in header", header->x_scale_factor);
931       return 1;
932     }
933 
934     if ((y_scale_factor <= 0) || !F64_IS_FINITE(y_scale_factor))
935     {
936       sprintf(laszip_dll->error, "invalid y scale_factor %g in header", header->y_scale_factor);
937       return 1;
938     }
939 
940     if ((z_scale_factor <= 0) || !F64_IS_FINITE(z_scale_factor))
941     {
942       sprintf(laszip_dll->error, "invalid z scale_factor %g in header", header->z_scale_factor);
943       return 1;
944     }
945 
946     F64 center_bb_x = (header->min_x + header->max_x) / 2;
947     F64 center_bb_y = (header->min_y + header->max_y) / 2;
948     F64 center_bb_z = (header->min_z + header->max_z) / 2;
949 
950     if (!F64_IS_FINITE(center_bb_x))
951     {
952       sprintf(laszip_dll->error, "invalid x coordinate at center of bounding box (min: %g max: %g)", header->min_x, header->max_x);
953       return 1;
954     }
955 
956     if (!F64_IS_FINITE(center_bb_y))
957     {
958       sprintf(laszip_dll->error, "invalid y coordinate at center of  bounding box (min: %g max: %g)", header->min_y, header->max_y);
959       return 1;
960     }
961 
962     if (!F64_IS_FINITE(center_bb_z))
963     {
964       sprintf(laszip_dll->error, "invalid z coordinate at center of  bounding box (min: %g max: %g)", header->min_z, header->max_z);
965       return 1;
966     }
967 
968     F64 x_offset = header->x_offset;
969     F64 y_offset = header->y_offset;
970     F64 z_offset = header->z_offset;
971 
972     header->x_offset = (I64_FLOOR(center_bb_x/x_scale_factor/10000000))*10000000*x_scale_factor;
973     header->y_offset = (I64_FLOOR(center_bb_y/y_scale_factor/10000000))*10000000*y_scale_factor;
974     header->z_offset = (I64_FLOOR(center_bb_z/z_scale_factor/10000000))*10000000*z_scale_factor;
975 
976     if (laszip_check_for_integer_overflow(pointer))
977     {
978       header->x_offset = x_offset;
979       header->y_offset = y_offset;
980       header->z_offset = z_offset;
981       return 1;
982     }
983   }
984   catch (...)
985   {
986     sprintf(laszip_dll->error, "internal error in laszip_auto_offset");
987     return 1;
988   }
989 
990   laszip_dll->error[0] = '\0';
991   return 0;
992 }
993 
994 /*---------------------------------------------------------------------------*/
995 LASZIP_API laszip_I32
laszip_set_point(laszip_POINTER pointer,const laszip_point_struct * point)996 laszip_set_point(
997     laszip_POINTER                     pointer
998     , const laszip_point_struct*       point
999 )
1000 {
1001   if (pointer == 0) return 1;
1002   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1003 
1004   try
1005   {
1006     if (point == 0)
1007     {
1008       sprintf(laszip_dll->error, "laszip_point_struct pointer 'point' is zero");
1009       return 1;
1010     }
1011 
1012     if (laszip_dll->reader)
1013     {
1014       sprintf(laszip_dll->error, "cannot set point for reader");
1015       return 1;
1016     }
1017 
1018     memcpy(&laszip_dll->point, point, ((U8*)&(laszip_dll->point.extra_bytes)) - ((U8*)&(laszip_dll->point.X)));
1019 
1020     if (laszip_dll->point.extra_bytes)
1021     {
1022       if (point->extra_bytes)
1023       {
1024         if (laszip_dll->point.num_extra_bytes == point->num_extra_bytes)
1025         {
1026           memcpy(laszip_dll->point.extra_bytes, point->extra_bytes, laszip_dll->point.num_extra_bytes);
1027         }
1028         else
1029         {
1030           sprintf(laszip_dll->error, "target point has %d extra bytes but source point has %d", laszip_dll->point.num_extra_bytes, point->num_extra_bytes);
1031           return 1;
1032         }
1033       }
1034       else if (!laszip_dll->compatibility_mode)
1035       {
1036         sprintf(laszip_dll->error, "target point has extra bytes but source point does not");
1037         return 1;
1038       }
1039     }
1040 /*
1041     else
1042     {
1043       if (point->extra_bytes)
1044       {
1045         sprintf(laszip_dll->error, "source point has extra bytes but target point does not");
1046         return 1;
1047       }
1048     }
1049 */
1050   }
1051   catch (...)
1052   {
1053     sprintf(laszip_dll->error, "internal error in laszip_set_point");
1054     return 1;
1055   }
1056 
1057   laszip_dll->error[0] = '\0';
1058   return 0;
1059 }
1060 
1061 /*---------------------------------------------------------------------------*/
1062 LASZIP_API laszip_I32
laszip_set_coordinates(laszip_POINTER pointer,const laszip_F64 * coordinates)1063 laszip_set_coordinates(
1064     laszip_POINTER                     pointer
1065     , const laszip_F64*                coordinates
1066 )
1067 {
1068   if (pointer == 0) return 1;
1069   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1070 
1071   try
1072   {
1073     if (coordinates == 0)
1074     {
1075       sprintf(laszip_dll->error, "laszip_F64 pointer 'coordinates' is zero");
1076       return 1;
1077     }
1078 
1079     if (laszip_dll->reader)
1080     {
1081       sprintf(laszip_dll->error, "cannot set coordinates for reader");
1082       return 1;
1083     }
1084 
1085     // get a pointer to the header
1086 
1087     laszip_header_struct* header = &(laszip_dll->header);
1088 
1089     // get a pointer to the point
1090 
1091     laszip_point_struct* point = &(laszip_dll->point);
1092 
1093     // set the coordinates
1094 
1095     point->X = I32_QUANTIZE((coordinates[0]-header->x_offset)/header->x_scale_factor);
1096     point->Y = I32_QUANTIZE((coordinates[1]-header->y_offset)/header->y_scale_factor);
1097     point->Z = I32_QUANTIZE((coordinates[2]-header->z_offset)/header->z_scale_factor);
1098   }
1099   catch (...)
1100   {
1101     sprintf(laszip_dll->error, "internal error in laszip_set_coordinates");
1102     return 1;
1103   }
1104 
1105   laszip_dll->error[0] = '\0';
1106   return 0;
1107 }
1108 
1109 /*---------------------------------------------------------------------------*/
1110 LASZIP_API laszip_I32
laszip_get_coordinates(laszip_POINTER pointer,laszip_F64 * coordinates)1111 laszip_get_coordinates(
1112     laszip_POINTER                     pointer
1113     , laszip_F64*                      coordinates
1114 )
1115 {
1116   if (pointer == 0) return 1;
1117   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1118 
1119   try
1120   {
1121     if (coordinates == 0)
1122     {
1123       sprintf(laszip_dll->error, "laszip_F64 pointer 'coordinates' is zero");
1124       return 1;
1125     }
1126 
1127     // get a pointer to the header
1128 
1129     laszip_header_struct* header = &(laszip_dll->header);
1130 
1131     // get a pointer to the point
1132 
1133     laszip_point_struct* point = &(laszip_dll->point);
1134 
1135     // get the coordinates
1136 
1137     coordinates[0] = header->x_scale_factor*point->X+header->x_offset;
1138     coordinates[1] = header->y_scale_factor*point->Y+header->y_offset;
1139     coordinates[2] = header->z_scale_factor*point->Z+header->z_offset;
1140   }
1141   catch (...)
1142   {
1143     sprintf(laszip_dll->error, "internal error in laszip_get_coordinates");
1144     return 1;
1145   }
1146 
1147   laszip_dll->error[0] = '\0';
1148   return 0;
1149 }
1150 
1151 /*---------------------------------------------------------------------------*/
1152 LASZIP_API laszip_I32
laszip_set_geokeys(laszip_POINTER pointer,laszip_U32 number,const laszip_geokey_struct * key_entries)1153 laszip_set_geokeys(
1154     laszip_POINTER                     pointer
1155     , laszip_U32                       number
1156     , const laszip_geokey_struct*      key_entries
1157 )
1158 {
1159   if (pointer == 0) return 1;
1160   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1161 
1162   try
1163   {
1164     if (number == 0)
1165     {
1166       sprintf(laszip_dll->error, "number of key_entries is zero");
1167       return 1;
1168     }
1169 
1170     if (key_entries == 0)
1171     {
1172       sprintf(laszip_dll->error, "laszip_geokey_struct pointer 'key_entries' is zero");
1173       return 1;
1174     }
1175 
1176     if (laszip_dll->reader)
1177     {
1178       sprintf(laszip_dll->error, "cannot set geokeys after reader was opened");
1179       return 1;
1180     }
1181 
1182     if (laszip_dll->writer)
1183     {
1184       sprintf(laszip_dll->error, "cannot set geokeys after writer was opened");
1185       return 1;
1186     }
1187 
1188     // create the geokey directory
1189 
1190     laszip_geokey_struct* key_entries_plus_one = new laszip_geokey_struct[number+1];
1191     if (key_entries_plus_one == 0)
1192     {
1193       sprintf(laszip_dll->error, "allocating laszip_geokey_struct[%u] array", number+1);
1194       return 1;
1195     }
1196     key_entries_plus_one[0].key_id = 1;            // aka key_directory_version
1197     key_entries_plus_one[0].tiff_tag_location = 1; // aka key_revision
1198     key_entries_plus_one[0].count = 0;             // aka minor_revision
1199     key_entries_plus_one[0].value_offset = number; // aka number_of_keys
1200     memcpy(key_entries_plus_one + 1, key_entries, sizeof(laszip_geokey_struct)*number);
1201 
1202     // add the VLR
1203 
1204     if (laszip_add_vlr(laszip_dll, "LASF_Projection", 34735, (laszip_U16)(8 + number*8), 0, (laszip_U8*)key_entries_plus_one))
1205     {
1206       sprintf(laszip_dll->error, "setting %u geodouble_params", number);
1207       return 1;
1208     }
1209   }
1210   catch (...)
1211   {
1212     sprintf(laszip_dll->error, "internal error in laszip_set_geokey_entries");
1213     return 1;
1214   }
1215 
1216   laszip_dll->error[0] = '\0';
1217   return 0;
1218 }
1219 
1220 /*---------------------------------------------------------------------------*/
1221 LASZIP_API laszip_I32
laszip_set_geodouble_params(laszip_POINTER pointer,laszip_U32 number,const laszip_F64 * geodouble_params)1222 laszip_set_geodouble_params(
1223     laszip_POINTER                     pointer
1224     , laszip_U32                       number
1225     , const laszip_F64*                geodouble_params
1226 )
1227 {
1228   if (pointer == 0) return 1;
1229   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1230 
1231   try
1232   {
1233     if (number == 0)
1234     {
1235       sprintf(laszip_dll->error, "number of geodouble_params is zero");
1236       return 1;
1237     }
1238 
1239     if (geodouble_params == 0)
1240     {
1241       sprintf(laszip_dll->error, "laszip_F64 pointer 'geodouble_params' is zero");
1242       return 1;
1243     }
1244 
1245     if (laszip_dll->reader)
1246     {
1247       sprintf(laszip_dll->error, "cannot set geodouble_params after reader was opened");
1248       return 1;
1249     }
1250 
1251     if (laszip_dll->writer)
1252     {
1253       sprintf(laszip_dll->error, "cannot set geodouble_params after writer was opened");
1254       return 1;
1255     }
1256 
1257     // add the VLR
1258 
1259     if (laszip_add_vlr(laszip_dll, "LASF_Projection", 34736, (laszip_U16)(number*8), 0, (laszip_U8*)geodouble_params))
1260     {
1261       sprintf(laszip_dll->error, "setting %u geodouble_params", number);
1262       return 1;
1263     }
1264   }
1265   catch (...)
1266   {
1267     sprintf(laszip_dll->error, "internal error in laszip_set_geodouble_params");
1268     return 1;
1269   }
1270 
1271   laszip_dll->error[0] = '\0';
1272   return 0;
1273 }
1274 
1275 /*---------------------------------------------------------------------------*/
1276 LASZIP_API laszip_I32
laszip_set_geoascii_params(laszip_POINTER pointer,laszip_U32 number,const laszip_CHAR * geoascii_params)1277 laszip_set_geoascii_params(
1278     laszip_POINTER                     pointer
1279     , laszip_U32                       number
1280     , const laszip_CHAR*               geoascii_params
1281 )
1282 {
1283   if (pointer == 0) return 1;
1284   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1285 
1286   try
1287   {
1288     if (number == 0)
1289     {
1290       sprintf(laszip_dll->error, "number of geoascii_params is zero");
1291       return 1;
1292     }
1293 
1294     if (geoascii_params == 0)
1295     {
1296       sprintf(laszip_dll->error, "laszip_CHAR pointer 'geoascii_params' is zero");
1297       return 1;
1298     }
1299 
1300     if (laszip_dll->reader)
1301     {
1302       sprintf(laszip_dll->error, "cannot set geoascii_params after reader was opened");
1303       return 1;
1304     }
1305 
1306     if (laszip_dll->writer)
1307     {
1308       sprintf(laszip_dll->error, "cannot set geoascii_params after writer was opened");
1309       return 1;
1310     }
1311 
1312     // add the VLR
1313 
1314     if (laszip_add_vlr(laszip_dll, "LASF_Projection", 34737, (laszip_U16)(number), 0, (laszip_U8*)geoascii_params))
1315     {
1316       sprintf(laszip_dll->error, "setting %u geoascii_params", number);
1317       return 1;
1318     }
1319   }
1320   catch (...)
1321   {
1322     sprintf(laszip_dll->error, "internal error in laszip_set_geoascii_params");
1323     return 1;
1324   }
1325 
1326   laszip_dll->error[0] = '\0';
1327   return 0;
1328 }
1329 
1330 /*---------------------------------------------------------------------------*/
1331 LASZIP_API laszip_I32
laszip_add_attribute(laszip_POINTER pointer,laszip_U32 type,const laszip_CHAR * name,const laszip_CHAR * description,laszip_F64 scale,laszip_F64 offset)1332 laszip_add_attribute(
1333     laszip_POINTER                     pointer
1334     , laszip_U32                       type
1335     , const laszip_CHAR*               name
1336     , const laszip_CHAR*               description
1337     , laszip_F64                       scale
1338     , laszip_F64                       offset
1339 )
1340 {
1341   if (pointer == 0) return 1;
1342   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1343 
1344   try
1345   {
1346     if (type > LAS_ATTRIBUTE_F64)
1347     {
1348       sprintf(laszip_dll->error, "laszip_U32 'type' is %u but needs to be between %d and %d", type, LAS_ATTRIBUTE_U8, LAS_ATTRIBUTE_F64);
1349       return 1;
1350     }
1351 
1352     if (name == 0)
1353     {
1354       sprintf(laszip_dll->error, "laszip_CHAR pointer 'name' is zero");
1355       return 1;
1356     }
1357 
1358     if (laszip_dll->reader)
1359     {
1360       sprintf(laszip_dll->error, "cannot add attribute after reader was opened");
1361       return 1;
1362     }
1363 
1364     if (laszip_dll->writer)
1365     {
1366       sprintf(laszip_dll->error, "cannot add attribute after writer was opened");
1367       return 1;
1368     }
1369 
1370     LASattribute lasattribute(type, name, description);
1371     lasattribute.set_scale(scale);
1372     lasattribute.set_offset(offset);
1373 
1374     if (laszip_dll->attributer == 0)
1375     {
1376       laszip_dll->attributer = new LASattributer;
1377       if (laszip_dll->attributer == 0)
1378       {
1379         sprintf(laszip_dll->error, "cannot allocate LASattributer");
1380         return 1;
1381       }
1382     }
1383 
1384     if (laszip_dll->attributer->add_attribute(lasattribute) == -1)
1385     {
1386       sprintf(laszip_dll->error, "cannot add attribute '%s' to attributer", name);
1387       return 1;
1388     }
1389 
1390     if (laszip_add_vlr(laszip_dll, "LASF_Spec\0\0\0\0\0\0", 4, (laszip_U16)(laszip_dll->attributer->number_attributes*sizeof(LASattribute)), 0, (laszip_U8*)laszip_dll->attributer->attributes))
1391     {
1392       sprintf(laszip_dll->error, "adding the new extra bytes VLR with the additional attribute '%s'", name);
1393       return 1;
1394     }
1395   }
1396   catch (...)
1397   {
1398     sprintf(laszip_dll->error, "internal error in laszip_add_attribute");
1399     return 1;
1400   }
1401 
1402   laszip_dll->error[0] = '\0';
1403   return 0;
1404 }
1405 
1406 /*---------------------------------------------------------------------------*/
1407 LASZIP_API laszip_I32
laszip_add_vlr(laszip_POINTER pointer,const laszip_CHAR * user_id,laszip_U16 record_id,laszip_U16 record_length_after_header,const laszip_CHAR * description,const laszip_U8 * data)1408 laszip_add_vlr(
1409     laszip_POINTER                     pointer
1410     , const laszip_CHAR*               user_id
1411     , laszip_U16                       record_id
1412     , laszip_U16                       record_length_after_header
1413     , const laszip_CHAR*               description
1414     , const laszip_U8*                 data
1415 )
1416 {
1417   if (pointer == 0) return 1;
1418   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1419 
1420   try
1421   {
1422     if (user_id == 0)
1423     {
1424       sprintf(laszip_dll->error, "laszip_CHAR pointer 'user_id' is zero");
1425       return 1;
1426     }
1427 
1428     if ((record_length_after_header > 0) && (data == 0))
1429     {
1430       sprintf(laszip_dll->error, "record_length_after_header of VLR is %u but data pointer is zero", (U32)record_length_after_header);
1431       return 1;
1432     }
1433 
1434     if (laszip_dll->reader)
1435     {
1436       sprintf(laszip_dll->error, "cannot add vlr after reader was opened");
1437       return 1;
1438     }
1439 
1440     if (laszip_dll->writer)
1441     {
1442       sprintf(laszip_dll->error, "cannot add vlr after writer was opened");
1443       return 1;
1444     }
1445 
1446     U32 i = 0;
1447 
1448     if (laszip_dll->header.vlrs)
1449     {
1450       // overwrite existing VLR ?
1451 
1452       for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
1453       {
1454         if ((strncmp(laszip_dll->header.vlrs[i].user_id, user_id, 16) == 0) && (laszip_dll->header.vlrs[i].record_id == record_id))
1455         {
1456           if (laszip_dll->header.vlrs[i].record_length_after_header)
1457           {
1458             laszip_dll->header.offset_to_point_data -= laszip_dll->header.vlrs[i].record_length_after_header;
1459             laszip_dll->header.vlrs[i].record_length_after_header = 0;
1460             delete [] laszip_dll->header.vlrs[i].data;
1461             laszip_dll->header.vlrs[i].data = 0;
1462           }
1463           break;
1464         }
1465       }
1466 
1467       // create new VLR
1468 
1469       if (i == laszip_dll->header.number_of_variable_length_records)
1470       {
1471         laszip_dll->header.number_of_variable_length_records++;
1472         laszip_dll->header.offset_to_point_data += 54;
1473         laszip_dll->header.vlrs = (laszip_vlr_struct*)realloc(laszip_dll->header.vlrs, sizeof(laszip_vlr_struct)*laszip_dll->header.number_of_variable_length_records);
1474         if (laszip_dll->header.vlrs == 0)
1475         {
1476           sprintf(laszip_dll->error, "reallocating vlrs[%u] array", laszip_dll->header.number_of_variable_length_records);
1477           return 1;
1478         }
1479       }
1480     }
1481     else
1482     {
1483       laszip_dll->header.number_of_variable_length_records = 1;
1484       laszip_dll->header.offset_to_point_data += 54;
1485       laszip_dll->header.vlrs = (laszip_vlr_struct*)malloc(sizeof(laszip_vlr_struct));
1486       if (laszip_dll->header.vlrs == 0)
1487       {
1488         sprintf(laszip_dll->error, "allocating vlrs[1] array");
1489         return 1;
1490       }
1491     }
1492 
1493     // zero the VLR
1494 
1495     memset(&(laszip_dll->header.vlrs[i]), 0, sizeof(laszip_vlr_struct));
1496 
1497     // copy the VLR
1498 
1499     laszip_dll->header.vlrs[i].reserved = 0x0;
1500     strncpy(laszip_dll->header.vlrs[i].user_id, user_id, 16);
1501     laszip_dll->header.vlrs[i].record_id = record_id;
1502     laszip_dll->header.vlrs[i].record_length_after_header = record_length_after_header;
1503     if (description)
1504     {
1505       strncpy(laszip_dll->header.vlrs[i].description, description, 32);
1506     }
1507     else
1508     {
1509       sprintf(laszip_dll->header.vlrs[i].description, "LASzip DLL %d.%d r%d (%d)", LASZIP_VERSION_MAJOR, LASZIP_VERSION_MINOR, LASZIP_VERSION_REVISION, LASZIP_VERSION_BUILD_DATE);
1510     }
1511     if (record_length_after_header)
1512     {
1513       laszip_dll->header.offset_to_point_data += record_length_after_header;
1514       laszip_dll->header.vlrs[i].data = new U8[record_length_after_header];
1515       memcpy(laszip_dll->header.vlrs[i].data, data, record_length_after_header);
1516     }
1517   }
1518   catch (...)
1519   {
1520     sprintf(laszip_dll->error, "internal error in laszip_add_vlr");
1521     return 1;
1522   }
1523 
1524   laszip_dll->error[0] = '\0';
1525   return 0;
1526 }
1527 
1528 /*---------------------------------------------------------------------------*/
1529 LASZIP_API laszip_I32
laszip_remove_vlr(laszip_POINTER pointer,const laszip_CHAR * user_id,laszip_U16 record_id)1530 laszip_remove_vlr(
1531     laszip_POINTER                     pointer
1532     , const laszip_CHAR*               user_id
1533     , laszip_U16                       record_id
1534 )
1535 {
1536   if (pointer == 0) return 1;
1537   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1538 
1539   try
1540   {
1541     if (user_id == 0)
1542     {
1543       sprintf(laszip_dll->error, "laszip_CHAR pointer 'user_id' is zero");
1544       return 1;
1545     }
1546 
1547     if (laszip_dll->reader)
1548     {
1549       sprintf(laszip_dll->error, "cannot remove vlr after reader was opened");
1550       return 1;
1551     }
1552 
1553     if (laszip_dll->writer)
1554     {
1555       sprintf(laszip_dll->error, "cannot remove vlr after writer was opened");
1556       return 1;
1557     }
1558 
1559     U32 i = 0;
1560 
1561     if (laszip_dll->header.vlrs)
1562     {
1563       for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
1564       {
1565         if ((strncmp(laszip_dll->header.vlrs[i].user_id, user_id, 16) == 0) && (laszip_dll->header.vlrs[i].record_id == record_id))
1566         {
1567           if (laszip_dll->header.vlrs[i].record_length_after_header)
1568           {
1569             laszip_dll->header.offset_to_point_data -= (54 + laszip_dll->header.vlrs[i].record_length_after_header);
1570             delete [] laszip_dll->header.vlrs[i].data;
1571             laszip_dll->header.vlrs[i].data = 0;
1572           }
1573           laszip_dll->header.number_of_variable_length_records--;
1574           for (/*i = i*/; i < laszip_dll->header.number_of_variable_length_records; i++)
1575           {
1576             laszip_dll->header.vlrs[i] = laszip_dll->header.vlrs[i+1];
1577           }
1578           if (laszip_dll->header.number_of_variable_length_records)
1579           {
1580             laszip_dll->header.vlrs = (laszip_vlr_struct*)realloc(laszip_dll->header.vlrs, sizeof(laszip_vlr_struct)*laszip_dll->header.number_of_variable_length_records);
1581             if (laszip_dll->header.vlrs == 0)
1582             {
1583               sprintf(laszip_dll->error, "reallocating vlrs[%u] array", laszip_dll->header.number_of_variable_length_records);
1584               return 1;
1585             }
1586           }
1587           else
1588           {
1589             free(laszip_dll->header.vlrs);
1590             laszip_dll->header.vlrs = 0;
1591           }
1592           i = U32_MAX;
1593           break;
1594         }
1595       }
1596       if (i != U32_MAX)
1597       {
1598         sprintf(laszip_dll->error, "cannot find VLR with user_id '%s' and record_id %d among the %u VLRs in the header", user_id, (I32)record_id, laszip_dll->header.number_of_variable_length_records);
1599         return 1;
1600       }
1601     }
1602     else
1603     {
1604       sprintf(laszip_dll->error, "cannot remove VLR with user_id '%s' and record_id %d because header has no VLRs", user_id, (I32)record_id);
1605       return 1;
1606     }
1607   }
1608   catch (...)
1609   {
1610     sprintf(laszip_dll->error, "internal error in laszip_add_vlr");
1611     return 1;
1612   }
1613 
1614   laszip_dll->error[0] = '\0';
1615   return 0;
1616 }
1617 
1618 /*---------------------------------------------------------------------------*/
1619 LASZIP_API laszip_I32
laszip_preserve_generating_software(laszip_POINTER pointer,const laszip_BOOL preserve)1620 laszip_preserve_generating_software(
1621     laszip_POINTER                     pointer
1622     , const laszip_BOOL                preserve
1623 )
1624 {
1625   if (pointer == 0) return 1;
1626   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1627 
1628   try
1629   {
1630     if (laszip_dll->reader)
1631     {
1632       sprintf(laszip_dll->error, "reader is already open");
1633       return 1;
1634     }
1635 
1636     if (laszip_dll->writer)
1637     {
1638       sprintf(laszip_dll->error, "writer is already open");
1639       return 1;
1640     }
1641 
1642     laszip_dll->preserve_generating_software = preserve;
1643   }
1644   catch (...)
1645   {
1646     sprintf(laszip_dll->error, "internal error in laszip_preserve_generating_software");
1647     return 1;
1648   }
1649 
1650   laszip_dll->error[0] = '\0';
1651   return 0;
1652 }
1653 
1654 
1655 /*---------------------------------------------------------------------------*/
1656 LASZIP_API laszip_I32
laszip_request_native_extension(laszip_POINTER pointer,const laszip_BOOL request)1657 laszip_request_native_extension(
1658     laszip_POINTER                     pointer
1659     , const laszip_BOOL                request
1660 )
1661 {
1662   if (pointer == 0) return 1;
1663   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1664 
1665   try
1666   {
1667     if (laszip_dll->reader)
1668     {
1669       sprintf(laszip_dll->error, "reader is already open");
1670       return 1;
1671     }
1672 
1673     if (laszip_dll->writer)
1674     {
1675       sprintf(laszip_dll->error, "writer is already open");
1676       return 1;
1677     }
1678 
1679     laszip_dll->request_native_extension = request;
1680 
1681     if (request) // only one should be on
1682     {
1683       laszip_dll->request_compatibility_mode = FALSE;
1684     }
1685   }
1686   catch (...)
1687   {
1688     sprintf(laszip_dll->error, "internal error in laszip_request_native_extension");
1689     return 1;
1690   }
1691 
1692   laszip_dll->error[0] = '\0';
1693   return 0;
1694 }
1695 
1696 /*---------------------------------------------------------------------------*/
1697 LASZIP_API laszip_I32
laszip_request_compatibility_mode(laszip_POINTER pointer,const laszip_BOOL request)1698 laszip_request_compatibility_mode(
1699     laszip_POINTER                     pointer
1700     , const laszip_BOOL                request
1701 )
1702 {
1703   if (pointer == 0) return 1;
1704   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1705 
1706   try
1707   {
1708     if (laszip_dll->reader)
1709     {
1710       sprintf(laszip_dll->error, "reader is already open");
1711       return 1;
1712     }
1713 
1714     if (laszip_dll->writer)
1715     {
1716       sprintf(laszip_dll->error, "writer is already open");
1717       return 1;
1718     }
1719 
1720     laszip_dll->request_compatibility_mode = request;
1721 
1722     if (request) // only one should be on
1723     {
1724       laszip_dll->request_native_extension = FALSE;
1725     }
1726   }
1727   catch (...)
1728   {
1729     sprintf(laszip_dll->error, "internal error in laszip_request_compatibility_mode");
1730     return 1;
1731   }
1732 
1733   laszip_dll->error[0] = '\0';
1734   return 0;
1735 }
1736 
1737 /*---------------------------------------------------------------------------*/
1738 LASZIP_API laszip_I32
laszip_set_chunk_size(laszip_POINTER pointer,const laszip_U32 chunk_size)1739 laszip_set_chunk_size(
1740     laszip_POINTER                     pointer
1741     , const laszip_U32                 chunk_size
1742 )
1743 {
1744   if (pointer == 0) return 1;
1745   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1746 
1747   try
1748   {
1749     if (laszip_dll->reader)
1750     {
1751       sprintf(laszip_dll->error, "reader is already open");
1752       return 1;
1753     }
1754 
1755     if (laszip_dll->writer)
1756     {
1757       sprintf(laszip_dll->error, "writer is already open");
1758       return 1;
1759     }
1760 
1761     laszip_dll->set_chunk_size = chunk_size;
1762   }
1763   catch (...)
1764   {
1765     sprintf(laszip_dll->error, "internal error in laszip_set_chunk_size");
1766     return 1;
1767   }
1768 
1769   laszip_dll->error[0] = '\0';
1770   return 0;
1771 }
1772 
1773 /*---------------------------------------------------------------------------*/
1774 LASZIP_API laszip_I32
laszip_create_spatial_index(laszip_POINTER pointer,const laszip_BOOL create,const laszip_BOOL append)1775 laszip_create_spatial_index(
1776     laszip_POINTER                     pointer
1777     , const laszip_BOOL                create
1778     , const laszip_BOOL                append
1779 )
1780 {
1781   if (pointer == 0) return 1;
1782   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1783 
1784   try
1785   {
1786     if (laszip_dll->reader)
1787     {
1788       sprintf(laszip_dll->error, "reader is already open");
1789       return 1;
1790     }
1791 
1792     if (laszip_dll->writer)
1793     {
1794       sprintf(laszip_dll->error, "writer is already open");
1795       return 1;
1796     }
1797 
1798     if (append)
1799     {
1800       sprintf(laszip_dll->error, "appending of spatial index not (yet) supported in this version");
1801       return 1;
1802     }
1803 
1804     laszip_dll->lax_create = create;
1805     laszip_dll->lax_append = append;
1806   }
1807   catch (...)
1808   {
1809     sprintf(laszip_dll->error, "internal error in laszip_create_spatial_index");
1810     return 1;
1811   }
1812 
1813   laszip_dll->error[0] = '\0';
1814   return 0;
1815 }
1816 
1817 /*---------------------------------------------------------------------------*/
1818 static I32
laszip_prepare_header_for_write(laszip_dll_struct * laszip_dll)1819 laszip_prepare_header_for_write(
1820     laszip_dll_struct*                 laszip_dll
1821 )
1822 {
1823   if ((laszip_dll->header.version_major != 1) || (laszip_dll->header.version_minor > 4))
1824   {
1825     sprintf(laszip_dll->error, "unknown LAS version %d.%d", (I32)laszip_dll->header.version_major, (I32)laszip_dll->header.version_minor);
1826     return 1;
1827   }
1828 
1829   // check counters
1830   U32 i;
1831 
1832   if (laszip_dll->header.point_data_format > 5)
1833   {
1834     // legacy counters are zero for new point types
1835 
1836     laszip_dll->header.number_of_point_records = 0;
1837     for (i = 0; i < 5; i++)
1838     {
1839       laszip_dll->header.number_of_points_by_return[i] = 0;
1840     }
1841   }
1842   else if (laszip_dll->header.version_minor > 3)
1843   {
1844     // legacy counters must be zero or consistent for old point types
1845 
1846     if (laszip_dll->header.number_of_point_records != laszip_dll->header.extended_number_of_point_records)
1847     {
1848       if (laszip_dll->header.number_of_point_records != 0)
1849       {
1850 #ifdef _WIN32
1851         sprintf(laszip_dll->error, "inconsistent number_of_point_records %u and extended_number_of_point_records %I64d", laszip_dll->header.number_of_point_records, laszip_dll->header.extended_number_of_point_records);
1852 #else
1853         sprintf(laszip_dll->error, "inconsistent number_of_point_records %u and extended_number_of_point_records %llu", laszip_dll->header.number_of_point_records, laszip_dll->header.extended_number_of_point_records);
1854 #endif
1855         return 1;
1856       }
1857       else if (laszip_dll->header.extended_number_of_point_records <= U32_MAX)
1858       {
1859         laszip_dll->header.number_of_point_records = (U32)laszip_dll->header.extended_number_of_point_records;
1860       }
1861     }
1862     for (i = 0; i < 5; i++)
1863     {
1864       if (laszip_dll->header.number_of_points_by_return[i] != laszip_dll->header.extended_number_of_points_by_return[i])
1865       {
1866         if (laszip_dll->header.number_of_points_by_return[i] != 0)
1867         {
1868 #ifdef _WIN32
1869           sprintf(laszip_dll->error, "inconsistent number_of_points_by_return[%u] %u and extended_number_of_points_by_return[%u] %I64d", i, laszip_dll->header.number_of_points_by_return[i], i, laszip_dll->header.extended_number_of_points_by_return[i]);
1870 #else
1871           sprintf(laszip_dll->error, "inconsistent number_of_points_by_return[%u] %u and extended_number_of_points_by_return[%u] %llu", i, laszip_dll->header.number_of_points_by_return[i], i, laszip_dll->header.extended_number_of_points_by_return[i]);
1872 #endif
1873           return 1;
1874         }
1875         else if (laszip_dll->header.extended_number_of_points_by_return[i] <= U32_MAX)
1876         {
1877           laszip_dll->header.number_of_points_by_return[i] = (U32)laszip_dll->header.extended_number_of_points_by_return[i];
1878         }
1879       }
1880     }
1881   }
1882 
1883   return 0;
1884 }
1885 
1886 /*---------------------------------------------------------------------------*/
1887 static I32
laszip_prepare_point_for_write(laszip_dll_struct * laszip_dll,const laszip_BOOL compress)1888 laszip_prepare_point_for_write(
1889     laszip_dll_struct*                 laszip_dll
1890     , const laszip_BOOL                compress
1891 )
1892 {
1893   U32 i;
1894 
1895   if (laszip_dll->header.point_data_format > 5)
1896   {
1897     // must be set for the new point types 6 or higher ...
1898 
1899     laszip_dll->point.extended_point_type = 1;
1900 
1901     if (laszip_dll->request_native_extension)
1902     {
1903       // we are *not* operating in compatibility mode
1904 
1905       laszip_dll->compatibility_mode = FALSE;
1906     }
1907     else if (laszip_dll->request_compatibility_mode)
1908     {
1909       // we are *not* using the native extension
1910 
1911       laszip_dll->request_native_extension = FALSE;
1912 
1913       // make sure there are no more than U32_MAX points
1914 
1915       if (laszip_dll->header.extended_number_of_point_records > U32_MAX)
1916       {
1917 #ifdef _WIN32
1918         sprintf(laszip_dll->error, "extended_number_of_point_records of %I64d is too much for 32-bit counters of compatibility mode", laszip_dll->header.extended_number_of_point_records);
1919 #else
1920         sprintf(laszip_dll->error, "extended_number_of_point_records of %llu is too much for 32-bit counters of compatibility mode", laszip_dll->header.extended_number_of_point_records);
1921 #endif
1922         return 1;
1923       }
1924 
1925       // copy 64-bit extended counters back into 32-bit legacy counters
1926 
1927       laszip_dll->header.number_of_point_records = (U32)(laszip_dll->header.extended_number_of_point_records);
1928       for (i = 0; i < 5; i++)
1929       {
1930         laszip_dll->header.number_of_points_by_return[i] = (U32)(laszip_dll->header.extended_number_of_points_by_return[i]);
1931       }
1932 
1933       // are there any "extra bytes" already ... ?
1934 
1935       I32 number_of_existing_extrabytes = 0;
1936 
1937       switch (laszip_dll->header.point_data_format)
1938       {
1939       case 6:
1940         number_of_existing_extrabytes = laszip_dll->header.point_data_record_length - 30;
1941         break;
1942       case 7:
1943         number_of_existing_extrabytes = laszip_dll->header.point_data_record_length - 36;
1944         break;
1945       case 8:
1946         number_of_existing_extrabytes = laszip_dll->header.point_data_record_length - 38;
1947         break;
1948       case 9:
1949         number_of_existing_extrabytes = laszip_dll->header.point_data_record_length - 59;
1950         break;
1951       case 10:
1952         number_of_existing_extrabytes = laszip_dll->header.point_data_record_length - 67;
1953         break;
1954       default:
1955         sprintf(laszip_dll->error, "unknown point_data_format %d", laszip_dll->header.point_data_format);
1956         return 1;
1957       }
1958 
1959       if (number_of_existing_extrabytes < 0)
1960       {
1961         sprintf(laszip_dll->error, "bad point_data_format %d point_data_record_length %d combination", laszip_dll->header.point_data_format, laszip_dll->header.point_data_record_length);
1962         return 1;
1963       }
1964 
1965       // downgrade to LAS 1.2 or LAS 1.3
1966       if (laszip_dll->header.point_data_format <= 8)
1967       {
1968         laszip_dll->header.version_minor = 2;
1969         // LAS 1.2 header is 148 bytes less than LAS 1.4+ header
1970         laszip_dll->header.header_size -= 148;
1971         laszip_dll->header.offset_to_point_data -= 148;
1972       }
1973       else
1974       {
1975         laszip_dll->header.version_minor = 3;
1976         // LAS 1.3 header is 140 bytes less than LAS 1.4+ header
1977         laszip_dll->header.header_size -= 140;
1978         laszip_dll->header.offset_to_point_data -= 140;
1979       }
1980       // turn off the bit indicating the presence of the OGC WKT
1981       laszip_dll->header.global_encoding &= ~(1<<4);
1982 
1983       // old point type is two bytes shorter
1984       laszip_dll->header.point_data_record_length -= 2;
1985       // but we add 5 bytes of attributes
1986       laszip_dll->header.point_data_record_length += 5;
1987 
1988       // create 2+2+4+148 bytes payload for compatibility VLR
1989       ByteStreamOutArray* out;
1990       if (IS_LITTLE_ENDIAN())
1991         out = new ByteStreamOutArrayLE();
1992       else
1993         out = new ByteStreamOutArrayBE();
1994       // write control info
1995       U16 laszip_version = (U16)LASZIP_VERSION_BUILD_DATE;
1996       out->put16bitsLE((U8*)&laszip_version);
1997       U16 compatible_version = 3;
1998       out->put16bitsLE((U8*)&compatible_version);
1999       U32 unused = 0;
2000       out->put32bitsLE((U8*)&unused);
2001       // write the 148 bytes of the extended LAS 1.4 header
2002       U64 start_of_waveform_data_packet_record = laszip_dll->header.start_of_waveform_data_packet_record;
2003       if (start_of_waveform_data_packet_record != 0)
2004       {
2005 #ifdef _WIN32
2006         fprintf(stderr,"WARNING: header->start_of_waveform_data_packet_record is %I64d. writing 0 instead.\n", start_of_waveform_data_packet_record);
2007 #else
2008         fprintf(stderr,"WARNING: header->start_of_waveform_data_packet_record is %llu. writing 0 instead.\n", start_of_waveform_data_packet_record);
2009 #endif
2010         start_of_waveform_data_packet_record = 0;
2011       }
2012       out->put64bitsLE((U8*)&start_of_waveform_data_packet_record);
2013       U64 start_of_first_extended_variable_length_record = laszip_dll->header.start_of_first_extended_variable_length_record;
2014       if (start_of_first_extended_variable_length_record != 0)
2015       {
2016 #ifdef _WIN32
2017         fprintf(stderr,"WARNING: EVLRs not supported. header->start_of_first_extended_variable_length_record is %I64d. writing 0 instead.\n", start_of_first_extended_variable_length_record);
2018 #else
2019         fprintf(stderr,"WARNING: EVLRs not supported. header->start_of_first_extended_variable_length_record is %llu. writing 0 instead.\n", start_of_first_extended_variable_length_record);
2020 #endif
2021         start_of_first_extended_variable_length_record = 0;
2022       }
2023       out->put64bitsLE((U8*)&start_of_first_extended_variable_length_record);
2024       U32 number_of_extended_variable_length_records = laszip_dll->header.number_of_extended_variable_length_records;
2025       if (number_of_extended_variable_length_records != 0)
2026       {
2027         fprintf(stderr,"WARNING: EVLRs not supported. header->number_of_extended_variable_length_records is %u. writing 0 instead.\n", number_of_extended_variable_length_records);
2028         number_of_extended_variable_length_records = 0;
2029       }
2030       out->put32bitsLE((U8*)&number_of_extended_variable_length_records);
2031       U64 extended_number_of_point_records;
2032       if (laszip_dll->header.number_of_point_records)
2033         extended_number_of_point_records = laszip_dll->header.number_of_point_records;
2034       else
2035         extended_number_of_point_records = laszip_dll->header.extended_number_of_point_records;
2036       out->put64bitsLE((U8*)&extended_number_of_point_records);
2037       U64 extended_number_of_points_by_return;
2038       for (i = 0; i < 15; i++)
2039       {
2040         if ((i < 5) && laszip_dll->header.number_of_points_by_return[i])
2041           extended_number_of_points_by_return = laszip_dll->header.number_of_points_by_return[i];
2042         else
2043           extended_number_of_points_by_return = laszip_dll->header.extended_number_of_points_by_return[i];
2044         out->put64bitsLE((U8*)&extended_number_of_points_by_return);
2045       }
2046 
2047       // add the compatibility VLR
2048 
2049       if (laszip_add_vlr(laszip_dll, "lascompatible\0\0", 22204, (laszip_U16)(2+2+4+148), 0, (laszip_U8*)out->takeData()))
2050       {
2051         sprintf(laszip_dll->error, "adding the compatibility VLR");
2052         return 1;
2053       }
2054       delete out;
2055 
2056       // if needed create an attributer to describe the "extra bytes"
2057 
2058       if (laszip_dll->attributer == 0)
2059       {
2060         laszip_dll->attributer = new LASattributer;
2061         if (laszip_dll->attributer == 0)
2062         {
2063           sprintf(laszip_dll->error, "cannot allocate LASattributer");
2064           return 1;
2065         }
2066       }
2067 
2068       // were there any pre-existing extra bytes
2069 
2070       if (number_of_existing_extrabytes > 0)
2071       {
2072         // make sure the existing "extra bytes" are documented
2073 
2074         if (laszip_dll->attributer->get_attributes_size() > number_of_existing_extrabytes)
2075         {
2076           sprintf(laszip_dll->error, "bad \"extra bytes\" VLR describes %d bytes more than points actually have", laszip_dll->attributer->get_attributes_size() - number_of_existing_extrabytes);
2077           return 1;
2078         }
2079         else if (laszip_dll->attributer->get_attributes_size() < number_of_existing_extrabytes)
2080         {
2081           // maybe the existing "extra bytes" are documented in a VLR
2082           if (laszip_dll->header.vlrs)
2083           {
2084             for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
2085             {
2086               if ((strcmp(laszip_dll->header.vlrs[i].user_id, "LASF_Spec") == 0) && (laszip_dll->header.vlrs[i].record_id == 4))
2087               {
2088                 laszip_dll->attributer->init_attributes(laszip_dll->header.vlrs[i].record_length_after_header/sizeof(LASattribute), (LASattribute*)laszip_dll->header.vlrs[i].data);
2089               }
2090             }
2091           }
2092 
2093           // describe any undocumented "extra bytes" as "unknown" U8  attributes
2094           for (I32 i = (I32)(laszip_dll->attributer->get_attributes_size()); i < number_of_existing_extrabytes; i++)
2095           {
2096             CHAR unknown_name[16];
2097             memset(unknown_name, 0, 16);
2098             sprintf(unknown_name, "unknown %d", i);
2099             LASattribute lasattribute_unknown(LAS_ATTRIBUTE_U8, unknown_name, unknown_name);
2100             if (laszip_dll->attributer->add_attribute(lasattribute_unknown) == -1)
2101             {
2102               sprintf(laszip_dll->error, "cannot add unknown U8 attribute '%s' of %d to attributer", unknown_name, number_of_existing_extrabytes);
2103               return 1;
2104             }
2105           }
2106         }
2107       }
2108 
2109       // create the "extra bytes" that store the newer LAS 1.4 point attributes
2110 
2111       // scan_angle (difference or remainder) is stored as a I16
2112       LASattribute lasattribute_scan_angle(LAS_ATTRIBUTE_I16, "LAS 1.4 scan angle", "additional attributes");
2113       lasattribute_scan_angle.set_scale(0.006);
2114       I32 index_scan_angle = laszip_dll->attributer->add_attribute(lasattribute_scan_angle);
2115       laszip_dll->start_scan_angle = laszip_dll->attributer->get_attribute_start(index_scan_angle);
2116       // extended returns stored as a U8
2117       LASattribute lasattribute_extended_returns(LAS_ATTRIBUTE_U8, "LAS 1.4 extended returns", "additional attributes");
2118       I32 index_extended_returns = laszip_dll->attributer->add_attribute(lasattribute_extended_returns);
2119       laszip_dll->start_extended_returns = laszip_dll->attributer->get_attribute_start(index_extended_returns);
2120       // classification stored as a U8
2121       LASattribute lasattribute_classification(LAS_ATTRIBUTE_U8, "LAS 1.4 classification", "additional attributes");
2122       I32 index_classification = laszip_dll->attributer->add_attribute(lasattribute_classification);
2123       laszip_dll->start_classification = laszip_dll->attributer->get_attribute_start(index_classification);
2124       // flags and channel stored as a U8
2125       LASattribute lasattribute_flags_and_channel(LAS_ATTRIBUTE_U8, "LAS 1.4 flags and channel", "additional attributes");
2126       I32 index_flags_and_channel = laszip_dll->attributer->add_attribute(lasattribute_flags_and_channel);
2127       laszip_dll->start_flags_and_channel = laszip_dll->attributer->get_attribute_start(index_flags_and_channel);
2128       // maybe store the NIR band as a U16
2129       if (laszip_dll->header.point_data_format == 8 || laszip_dll->header.point_data_format == 10)
2130       {
2131         // the NIR band is stored as a U16
2132         LASattribute lasattribute_NIR_band(LAS_ATTRIBUTE_U16, "LAS 1.4 NIR band", "additional attributes");
2133         I32 index_NIR_band = laszip_dll->attributer->add_attribute(lasattribute_NIR_band);
2134         laszip_dll->start_NIR_band = laszip_dll->attributer->get_attribute_start(index_NIR_band);
2135       }
2136       else
2137       {
2138         laszip_dll->start_NIR_band = -1;
2139       }
2140 
2141       // add the extra bytes VLR with the additional attributes
2142 
2143       if (laszip_add_vlr(laszip_dll, "LASF_Spec\0\0\0\0\0\0", 4, (laszip_U16)(laszip_dll->attributer->number_attributes*sizeof(LASattribute)), 0, (laszip_U8*)laszip_dll->attributer->attributes))
2144       {
2145         sprintf(laszip_dll->error, "adding the extra bytes VLR with the additional attributes");
2146         return 1;
2147       }
2148 
2149       // update point type
2150 
2151       if (laszip_dll->header.point_data_format == 6)
2152       {
2153         laszip_dll->header.point_data_format = 1;
2154       }
2155       else if (laszip_dll->header.point_data_format <= 8)
2156       {
2157         laszip_dll->header.point_data_format = 3;
2158       }
2159       else // 9->4 and 10->5
2160       {
2161         laszip_dll->header.point_data_format -= 5;
2162       }
2163 
2164       // we are operating in compatibility mode
2165       laszip_dll->compatibility_mode = TRUE;
2166     }
2167     else if (compress)
2168     {
2169       sprintf(laszip_dll->error, "LASzip DLL %d.%d r%d (%d) cannot compress point data format %d without requesting 'compatibility mode'", LASZIP_VERSION_MAJOR, LASZIP_VERSION_MINOR, LASZIP_VERSION_REVISION, LASZIP_VERSION_BUILD_DATE, (I32)laszip_dll->header.point_data_format);
2170       return 1;
2171     }
2172   }
2173   else
2174   {
2175     // must *not* be set for the old point type 5 or lower
2176 
2177     laszip_dll->point.extended_point_type = 0;
2178 
2179     // we are *not* operating in compatibility mode
2180 
2181     laszip_dll->compatibility_mode = FALSE;
2182   }
2183 
2184   return 0;
2185 }
2186 
2187 /*---------------------------------------------------------------------------*/
2188 static I32
laszip_prepare_vlrs_for_write(laszip_dll_struct * laszip_dll)2189 laszip_prepare_vlrs_for_write(
2190     laszip_dll_struct*                 laszip_dll
2191 )
2192 {
2193   U32 i, vlrs_size = 0;
2194 
2195   if (laszip_dll->header.number_of_variable_length_records)
2196   {
2197     if (laszip_dll->header.vlrs == 0)
2198     {
2199       sprintf(laszip_dll->error, "number_of_variable_length_records is %u but vlrs pointer is zero", laszip_dll->header.number_of_variable_length_records);
2200       return 1;
2201     }
2202 
2203     for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
2204     {
2205       vlrs_size += 54;
2206       if (laszip_dll->header.vlrs[i].record_length_after_header)
2207       {
2208         if (laszip_dll->header.vlrs == 0)
2209         {
2210           sprintf(laszip_dll->error, "vlrs[%u].record_length_after_header is %u but vlrs[%u].data pointer is zero", i, laszip_dll->header.vlrs[i].record_length_after_header, i);
2211           return 1;
2212         }
2213         vlrs_size += laszip_dll->header.vlrs[i].record_length_after_header;
2214       }
2215     }
2216   }
2217 
2218   if ((vlrs_size + laszip_dll->header.header_size + laszip_dll->header.user_data_after_header_size) != laszip_dll->header.offset_to_point_data)
2219   {
2220     sprintf(laszip_dll->error,"header_size (%u) plus vlrs_size (%u) plus user_data_after_header_size (%u) does not equal offset_to_point_data (%u)", (U32)laszip_dll->header.header_size, vlrs_size, laszip_dll->header.user_data_after_header_size, laszip_dll->header.offset_to_point_data);
2221     return 1;
2222   }
2223 
2224   return 0;
2225 }
2226 
2227 /*---------------------------------------------------------------------------*/
2228 static U32
laszip_vrl_payload_size(const LASzip * laszip)2229 laszip_vrl_payload_size(
2230     const LASzip*                      laszip
2231 )
2232 {
2233   return 34 + (6 * laszip->num_items);
2234 }
2235 
2236 /*---------------------------------------------------------------------------*/
2237 static I32
write_laszip_vlr_header(laszip_dll_struct * laszip_dll,const LASzip * laszip,ByteStreamOut * out)2238 write_laszip_vlr_header(
2239     laszip_dll_struct*                 laszip_dll
2240     , const LASzip*                    laszip
2241     , ByteStreamOut*                   out
2242 )
2243 {
2244   // write the LASzip VLR header
2245 
2246   U16 reserved = 0x0;
2247   try { out->put16bitsLE((U8*)&reserved); } catch(...)
2248   {
2249     sprintf(laszip_dll->error, "writing LASzip VLR header.reserved");
2250     return 1;
2251   }
2252   U8 user_id[16] = "laszip encoded\0";
2253   try { out->putBytes((U8*)user_id, 16); } catch(...)
2254   {
2255     sprintf(laszip_dll->error, "writing LASzip VLR header.user_id");
2256     return 1;
2257   }
2258   U16 record_id = 22204;
2259   try { out->put16bitsLE((U8*)&record_id); } catch(...)
2260   {
2261     sprintf(laszip_dll->error, "writing LASzip VLR header.record_id");
2262     return 1;
2263   }
2264   U16 record_length_after_header = (U16)laszip_vrl_payload_size(laszip);
2265   try { out->put16bitsLE((U8*)&record_length_after_header); } catch(...)
2266   {
2267     sprintf(laszip_dll->error, "writing LASzip VLR header.record_length_after_header");
2268     return 1;
2269   }
2270   CHAR description[32];
2271   memset(description, 0, 32);
2272   sprintf(description, "LASzip DLL %d.%d r%d (%d)", LASZIP_VERSION_MAJOR, LASZIP_VERSION_MINOR, LASZIP_VERSION_REVISION, LASZIP_VERSION_BUILD_DATE);
2273   try { out->putBytes((U8*)description, 32); } catch(...)
2274   {
2275     sprintf(laszip_dll->error, "writing LASzip VLR header.description");
2276     return 1;
2277   }
2278 
2279   return 0;
2280 }
2281 
2282 /*---------------------------------------------------------------------------*/
2283 static I32
write_laszip_vlr_payload(laszip_dll_struct * laszip_dll,const LASzip * laszip,ByteStreamOut * out)2284 write_laszip_vlr_payload(
2285     laszip_dll_struct*                 laszip_dll
2286     , const LASzip*                    laszip
2287     , ByteStreamOut*                   out
2288 )
2289 {
2290   // write the LASzip VLR payload
2291 
2292   //     U16  compressor                2 bytes
2293   //     U32  coder                     2 bytes
2294   //     U8   version_major             1 byte
2295   //     U8   version_minor             1 byte
2296   //     U16  version_revision          2 bytes
2297   //     U32  options                   4 bytes
2298   //     I32  chunk_size                4 bytes
2299   //     I64  number_of_special_evlrs   8 bytes
2300   //     I64  offset_to_special_evlrs   8 bytes
2301   //     U16  num_items                 2 bytes
2302   //        U16 type                2 bytes * num_items
2303   //        U16 size                2 bytes * num_items
2304   //        U16 version             2 bytes * num_items
2305   // which totals 34+6*num_items
2306 
2307   try { out->put16bitsLE((const U8*)&(laszip->compressor)); } catch(...)
2308   {
2309     sprintf(laszip_dll->error, "writing compressor %d", (I32)laszip->compressor);
2310     return 1;
2311   }
2312   try { out->put16bitsLE((const U8*)&(laszip->coder)); } catch(...)
2313   {
2314     sprintf(laszip_dll->error, "writing coder %d", (I32)laszip->coder);
2315     return 1;
2316   }
2317   try { out->putBytes((const U8*)&(laszip->version_major), 1); } catch(...)
2318   {
2319     sprintf(laszip_dll->error, "writing version_major %d", (I32)laszip->version_major);
2320     return 1;
2321   }
2322   try { out->putBytes((const U8*)&(laszip->version_minor), 1); } catch(...)
2323   {
2324     sprintf(laszip_dll->error, "writing version_minor %d", (I32)laszip->version_minor);
2325     return 1;
2326   }
2327   try { out->put16bitsLE((const U8*)&(laszip->version_revision)); } catch(...)
2328   {
2329     sprintf(laszip_dll->error, "writing version_revision %d", (I32)laszip->version_revision);
2330     return 1;
2331   }
2332   try { out->put32bitsLE((const U8*)&(laszip->options)); } catch(...)
2333   {
2334     sprintf(laszip_dll->error, "writing options %u", laszip->options);
2335     return 1;
2336   }
2337   try { out->put32bitsLE((const U8*)&(laszip->chunk_size)); } catch(...)
2338   {
2339     sprintf(laszip_dll->error, "writing chunk_size %u", laszip->chunk_size);
2340     return 1;
2341   }
2342   try { out->put64bitsLE((const U8*)&(laszip->number_of_special_evlrs)); } catch(...)
2343   {
2344     sprintf(laszip_dll->error, "writing number_of_special_evlrs %d", (I32)laszip->number_of_special_evlrs);
2345     return 1;
2346   }
2347   try { out->put64bitsLE((const U8*)&(laszip->offset_to_special_evlrs)); } catch(...)
2348   {
2349     sprintf(laszip_dll->error, "writing offset_to_special_evlrs %d", (I32)laszip->offset_to_special_evlrs);
2350     return 1;
2351   }
2352   try { out->put16bitsLE((const U8*)&(laszip->num_items)); } catch(...)
2353   {
2354     sprintf(laszip_dll->error, "writing num_items %d", (I32)laszip->num_items);
2355     return 1;
2356   }
2357 
2358   U32 j;
2359   for (j = 0; j < laszip->num_items; j++)
2360   {
2361     U16 type = (U16)(laszip->items[j].type);
2362     try { out->put16bitsLE((const U8*)&type); } catch(...)
2363     {
2364       sprintf(laszip_dll->error, "writing type %d of item %d", (I32)laszip->items[j].type, j);
2365       return 1;
2366     }
2367     try { out->put16bitsLE((const U8*)&(laszip->items[j].size)); } catch(...)
2368     {
2369       sprintf(laszip_dll->error, "writing size %d of item %d", (I32)laszip->items[j].size, j);
2370       return 1;
2371     }
2372     try { out->put16bitsLE((const U8*)&(laszip->items[j].version)); } catch(...)
2373     {
2374       sprintf(laszip_dll->error, "writing version %d of item %d", (I32)laszip->items[j].version, j);
2375       return 1;
2376     }
2377   }
2378   return 0;
2379 }
2380 
2381 /*---------------------------------------------------------------------------*/
2382 static I32
laszip_write_header(laszip_dll_struct * laszip_dll,const LASzip * laszip,const laszip_BOOL compress)2383 laszip_write_header(
2384     laszip_dll_struct*                 laszip_dll
2385     , const LASzip*                    laszip
2386     , const laszip_BOOL                compress
2387 )
2388 {
2389   U32 i;
2390 
2391   try { laszip_dll->streamout->putBytes((const U8*)"LASF", 4); } catch(...)
2392   {
2393     sprintf(laszip_dll->error, "writing header.file_signature");
2394     return 1;
2395   }
2396   try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.file_source_ID)); } catch(...)
2397   {
2398     sprintf(laszip_dll->error, "writing header.file_source_ID");
2399     return 1;
2400   }
2401   try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.global_encoding)); } catch(...)
2402   {
2403     sprintf(laszip_dll->error, "writing header.global_encoding");
2404     return 1;
2405   }
2406   try { laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->header.project_ID_GUID_data_1)); } catch(...)
2407   {
2408     sprintf(laszip_dll->error, "writing header.project_ID_GUID_data_1");
2409     return 1;
2410   }
2411   try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.project_ID_GUID_data_2)); } catch(...)
2412   {
2413     sprintf(laszip_dll->error, "writing header.project_ID_GUID_data_2");
2414     return 1;
2415   }
2416   try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.project_ID_GUID_data_3)); } catch(...)
2417   {
2418     sprintf(laszip_dll->error, "writing header.project_ID_GUID_data_3");
2419     return 1;
2420   }
2421   try { laszip_dll->streamout->putBytes((const U8*)laszip_dll->header.project_ID_GUID_data_4, 8); } catch(...)
2422   {
2423     sprintf(laszip_dll->error, "writing header.project_ID_GUID_data_4");
2424     return 1;
2425   }
2426   try { laszip_dll->streamout->putBytes((const U8*)&(laszip_dll->header.version_major), 1); } catch(...)
2427   {
2428     sprintf(laszip_dll->error, "writing header.version_major");
2429     return 1;
2430   }
2431   try { laszip_dll->streamout->putBytes((const U8*)&(laszip_dll->header.version_minor), 1); } catch(...)
2432   {
2433     sprintf(laszip_dll->error, "writing header.version_minor");
2434     return 1;
2435   }
2436   try { laszip_dll->streamout->putBytes((const U8*)laszip_dll->header.system_identifier, 32); } catch(...)
2437   {
2438     sprintf(laszip_dll->error, "writing header.system_identifier");
2439     return 1;
2440   }
2441   if (!laszip_dll->preserve_generating_software)
2442   {
2443     memset(laszip_dll->header.generating_software, 0, 32);
2444     sprintf(laszip_dll->header.generating_software, "LASzip DLL %d.%d r%d (%d)", LASZIP_VERSION_MAJOR, LASZIP_VERSION_MINOR, LASZIP_VERSION_REVISION, LASZIP_VERSION_BUILD_DATE);
2445   }
2446   try { laszip_dll->streamout->putBytes((const U8*)laszip_dll->header.generating_software, 32); } catch(...)
2447   {
2448     sprintf(laszip_dll->error, "writing header.generating_software");
2449     return 1;
2450   }
2451   try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.file_creation_day)); } catch(...)
2452   {
2453     sprintf(laszip_dll->error, "writing header.file_creation_day");
2454     return 1;
2455   }
2456   try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.file_creation_year)); } catch(...)
2457   {
2458     sprintf(laszip_dll->error, "writing header.file_creation_year");
2459     return 1;
2460   }
2461   try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.header_size)); } catch(...)
2462   {
2463     sprintf(laszip_dll->error, "writing header.header_size");
2464     return 1;
2465   }
2466   if (compress)
2467   {
2468     laszip_dll->header.offset_to_point_data += (54 + laszip_vrl_payload_size(laszip));
2469   }
2470   try { laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->header.offset_to_point_data)); } catch(...)
2471   {
2472     sprintf(laszip_dll->error, "writing header.offset_to_point_data");
2473     return 1;
2474   }
2475   if (compress)
2476   {
2477     laszip_dll->header.offset_to_point_data -= (54 + laszip_vrl_payload_size(laszip));
2478     laszip_dll->header.number_of_variable_length_records += 1;
2479   }
2480   try { laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->header.number_of_variable_length_records)); } catch(...)
2481   {
2482     sprintf(laszip_dll->error, "writing header.number_of_variable_length_records");
2483     return 1;
2484   }
2485   if (compress)
2486   {
2487     laszip_dll->header.number_of_variable_length_records -= 1;
2488     laszip_dll->header.point_data_format |= 128;
2489   }
2490   try { laszip_dll->streamout->putBytes((const U8*)&(laszip_dll->header.point_data_format), 1); } catch(...)
2491   {
2492     sprintf(laszip_dll->error, "writing header.point_data_format");
2493     return 1;
2494   }
2495   if (compress)
2496   {
2497     laszip_dll->header.point_data_format &= 127;
2498   }
2499   try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.point_data_record_length)); } catch(...)
2500   {
2501     sprintf(laszip_dll->error, "writing header.point_data_record_length");
2502     return 1;
2503   }
2504   try { laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->header.number_of_point_records)); } catch(...)
2505   {
2506     sprintf(laszip_dll->error, "writing header.number_of_point_records");
2507     return 1;
2508   }
2509   for (i = 0; i < 5; i++)
2510   {
2511     try { laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->header.number_of_points_by_return[i])); } catch(...)
2512     {
2513       sprintf(laszip_dll->error, "writing header.number_of_points_by_return %d", i);
2514       return 1;
2515     }
2516   }
2517   try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.x_scale_factor)); } catch(...)
2518   {
2519     sprintf(laszip_dll->error, "writing header.x_scale_factor");
2520     return 1;
2521   }
2522   try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.y_scale_factor)); } catch(...)
2523   {
2524     sprintf(laszip_dll->error, "writing header.y_scale_factor");
2525     return 1;
2526   }
2527   try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.z_scale_factor)); } catch(...)
2528   {
2529     sprintf(laszip_dll->error, "writing header.z_scale_factor");
2530     return 1;
2531   }
2532   try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.x_offset)); } catch(...)
2533   {
2534     sprintf(laszip_dll->error, "writing header.x_offset");
2535     return 1;
2536   }
2537   try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.y_offset)); } catch(...)
2538   {
2539     sprintf(laszip_dll->error, "writing header.y_offset");
2540     return 1;
2541   }
2542   try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.z_offset)); } catch(...)
2543   {
2544     sprintf(laszip_dll->error, "writing header.z_offset");
2545     return 1;
2546   }
2547   try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.max_x)); } catch(...)
2548   {
2549     sprintf(laszip_dll->error, "writing header.max_x");
2550     return 1;
2551   }
2552   try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.min_x)); } catch(...)
2553   {
2554     sprintf(laszip_dll->error, "writing header.min_x");
2555     return 1;
2556   }
2557   try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.max_y)); } catch(...)
2558   {
2559     sprintf(laszip_dll->error, "writing header.max_y");
2560     return 1;
2561   }
2562   try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.min_y)); } catch(...)
2563   {
2564     sprintf(laszip_dll->error, "writing header.min_y");
2565     return 1;
2566   }
2567   try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.max_z)); } catch(...)
2568   {
2569     sprintf(laszip_dll->error, "writing header.max_z");
2570     return 1;
2571   }
2572   try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.min_z)); } catch(...)
2573   {
2574     sprintf(laszip_dll->error, "writing header.min_z");
2575     return 1;
2576   }
2577 
2578   // special handling for LAS 1.3
2579   if ((laszip_dll->header.version_major == 1) && (laszip_dll->header.version_minor >= 3))
2580   {
2581     if (laszip_dll->header.header_size < 235)
2582     {
2583       sprintf(laszip_dll->error, "for LAS 1.%d header_size should at least be 235 but it is only %d", laszip_dll->header.version_minor, laszip_dll->header.header_size);
2584       return 1;
2585     }
2586     else
2587     {
2588       if (laszip_dll->header.start_of_waveform_data_packet_record != 0)
2589       {
2590 #ifdef _WIN32
2591         sprintf(laszip_dll->warning, "header.start_of_waveform_data_packet_record is %I64d. writing 0 instead.", laszip_dll->header.start_of_waveform_data_packet_record);
2592 #else
2593         sprintf(laszip_dll->warning, "header.start_of_waveform_data_packet_record is %llu. writing 0 instead.", laszip_dll->header.start_of_waveform_data_packet_record);
2594 #endif
2595         laszip_dll->header.start_of_waveform_data_packet_record = 0;
2596       }
2597       try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.start_of_waveform_data_packet_record)); } catch(...)
2598       {
2599         sprintf(laszip_dll->error, "writing header.start_of_waveform_data_packet_record");
2600         return 1;
2601       }
2602       laszip_dll->header.user_data_in_header_size = laszip_dll->header.header_size - 235;
2603     }
2604   }
2605   else
2606   {
2607     laszip_dll->header.user_data_in_header_size = laszip_dll->header.header_size - 227;
2608   }
2609 
2610   // special handling for LAS 1.4
2611   if ((laszip_dll->header.version_major == 1) && (laszip_dll->header.version_minor >= 4))
2612   {
2613     if (laszip_dll->header.header_size < 375)
2614     {
2615       sprintf(laszip_dll->error, "for LAS 1.%d header_size should at least be 375 but it is only %d", laszip_dll->header.version_minor, laszip_dll->header.header_size);
2616       return 1;
2617     }
2618     else
2619     {
2620       try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.start_of_first_extended_variable_length_record)); } catch(...)
2621       {
2622         sprintf(laszip_dll->error, "writing header.start_of_first_extended_variable_length_record");
2623         return 1;
2624       }
2625       try { laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->header.number_of_extended_variable_length_records)); } catch(...)
2626       {
2627         sprintf(laszip_dll->error, "writing header.number_of_extended_variable_length_records");
2628         return 1;
2629       }
2630       try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.extended_number_of_point_records)); } catch(...)
2631       {
2632         sprintf(laszip_dll->error, "writing header.extended_number_of_point_records");
2633         return 1;
2634       }
2635       for (i = 0; i < 15; i++)
2636       {
2637         try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.extended_number_of_points_by_return[i])); } catch(...)
2638         {
2639           sprintf(laszip_dll->error, "writing header.extended_number_of_points_by_return[%d]", i);
2640           return 1;
2641         }
2642       }
2643       laszip_dll->header.user_data_in_header_size = laszip_dll->header.header_size - 375;
2644     }
2645   }
2646 
2647   // write any number of user-defined bytes that might have been added to the header
2648   if (laszip_dll->header.user_data_in_header_size)
2649   {
2650     try { laszip_dll->streamout->putBytes((const U8*)laszip_dll->header.user_data_in_header, laszip_dll->header.user_data_in_header_size); } catch(...)
2651     {
2652       sprintf(laszip_dll->error, "writing %d bytes of data into header.user_data_in_header", laszip_dll->header.user_data_in_header_size);
2653       return 1;
2654     }
2655   }
2656 
2657   // write variable length records into the header
2658 
2659   if (laszip_dll->header.number_of_variable_length_records)
2660   {
2661     U32 i;
2662 
2663     for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
2664     {
2665       // write variable length records variable after variable (to avoid alignment issues)
2666 
2667       try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.vlrs[i].reserved)); } catch(...)
2668       {
2669         sprintf(laszip_dll->error, "writing header.vlrs[%d].reserved", i);
2670         return 1;
2671       }
2672 
2673       try { laszip_dll->streamout->putBytes((const U8*)laszip_dll->header.vlrs[i].user_id, 16); } catch(...)
2674       {
2675         sprintf(laszip_dll->error, "writing header.vlrs[%d].user_id", i);
2676         return 1;
2677       }
2678       try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.vlrs[i].record_id)); } catch(...)
2679       {
2680         sprintf(laszip_dll->error, "writing header.vlrs[%d].record_id", i);
2681         return 1;
2682       }
2683       try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.vlrs[i].record_length_after_header)); } catch(...)
2684       {
2685         sprintf(laszip_dll->error, "writing header.vlrs[%d].record_length_after_header", i);
2686         return 1;
2687       }
2688       try { laszip_dll->streamout->putBytes((const U8*)laszip_dll->header.vlrs[i].description, 32); } catch(...)
2689       {
2690         sprintf(laszip_dll->error, "writing header.vlrs[%d].description", i);
2691         return 1;
2692       }
2693 
2694       // write data following the header of the variable length record
2695 
2696       if (laszip_dll->header.vlrs[i].record_length_after_header)
2697       {
2698         try { laszip_dll->streamout->putBytes(laszip_dll->header.vlrs[i].data, laszip_dll->header.vlrs[i].record_length_after_header); } catch(...)
2699         {
2700           sprintf(laszip_dll->error, "writing %d bytes of data into header.vlrs[%d].data", laszip_dll->header.vlrs[i].record_length_after_header, i);
2701           return 1;
2702         }
2703       }
2704     }
2705   }
2706 
2707   if (compress)
2708   {
2709     // write the LASzip VLR header
2710 
2711     if (write_laszip_vlr_header(laszip_dll, laszip, laszip_dll->streamout))
2712     {
2713       return 1;
2714     }
2715 
2716     // write the LASzip VLR payload
2717 
2718     if (write_laszip_vlr_payload(laszip_dll, laszip, laszip_dll->streamout))
2719     {
2720       return 1;
2721     }
2722   }
2723 
2724   // write any number of user-defined bytes that might have been added after the header
2725 
2726   if (laszip_dll->header.user_data_after_header_size)
2727   {
2728     try { laszip_dll->streamout->putBytes((const U8*)laszip_dll->header.user_data_after_header, laszip_dll->header.user_data_after_header_size); } catch(...)
2729     {
2730       sprintf(laszip_dll->error, "writing %u bytes of data into header.user_data_after_header", laszip_dll->header.user_data_after_header_size);
2731       return 1;
2732     }
2733   }
2734 
2735   return 0;
2736 }
2737 
2738 /*----------------------------------------------------------------------------*/
create_point_writer(laszip_dll_struct * laszip_dll,const LASzip * laszip)2739 laszip_I32 create_point_writer
2740 (
2741     laszip_dll_struct *laszip_dll
2742     , const LASzip *laszip
2743 )
2744 {
2745   // create the point writer
2746   laszip_dll->writer = new LASwritePoint();
2747   if (laszip_dll->writer == 0)
2748   {
2749     sprintf(laszip_dll->error, "could not alloc LASwritePoint");
2750     return 1;
2751   }
2752 
2753   if (!laszip_dll->writer->setup(laszip->num_items, laszip->items, laszip))
2754   {
2755     sprintf(laszip_dll->error, "setup of LASwritePoint failed");
2756     return 1;
2757   }
2758 
2759   if (!laszip_dll->writer->init(laszip_dll->streamout))
2760   {
2761     sprintf(laszip_dll->error, "init of LASwritePoint failed");
2762     return 1;
2763   }
2764 
2765   return 0;
2766 }
2767 
2768 /*---------------------------------------------------------------------------*/
2769 static I32
setup_laszip_items(laszip_dll_struct * laszip_dll,LASzip * laszip,laszip_BOOL compress)2770 setup_laszip_items(
2771     laszip_dll_struct*                 laszip_dll
2772     , LASzip*                          laszip
2773     , laszip_BOOL                      compress
2774 )
2775 {
2776   laszip_U8 point_type = laszip_dll->header.point_data_format;
2777   laszip_U16 point_size = laszip_dll->header.point_data_record_length;
2778 
2779   if ((point_type > 5) && laszip_dll->request_compatibility_mode)
2780   {
2781     if (!laszip->request_compatibility_mode(1))
2782     {
2783       sprintf(laszip_dll->error, "requesting 'compatibility mode' has failed");
2784       return 1;
2785     }
2786   }
2787 
2788   // create point items in the LASzip structure from point format and size
2789 
2790   if (!laszip->setup(point_type, point_size, LASZIP_COMPRESSOR_NONE))
2791   {
2792     sprintf(laszip_dll->error, "invalid combination of point_type %d and point_size %d", (I32)point_type, (I32)point_size);
2793     return 1;
2794   }
2795 
2796   // compute offsets (or points item pointers) for data transfer from the point items
2797 
2798   if (laszip_dll->point_items)
2799   {
2800     delete [] laszip_dll->point_items;
2801   }
2802 
2803   laszip_dll->point_items = new U8*[laszip->num_items];
2804 
2805   if (laszip_dll->point_items == 0)
2806   {
2807     sprintf(laszip_dll->error, "could not alloc point_items");
2808     return 1;
2809   }
2810 
2811   for (size_t i = 0; i < laszip->num_items; i++)
2812   {
2813     switch (laszip->items[i].type)
2814     {
2815     case LASitem::POINT10:
2816     case LASitem::POINT14:
2817       laszip_dll->point_items[i] = (U8*)&(laszip_dll->point.X);
2818       break;
2819     case LASitem::GPSTIME11:
2820       laszip_dll->point_items[i] = (U8*)&(laszip_dll->point.gps_time);
2821       break;
2822     case LASitem::RGB12:
2823     case LASitem::RGB14:
2824     case LASitem::RGBNIR14:
2825       laszip_dll->point_items[i] = (U8*)laszip_dll->point.rgb;
2826       break;
2827     case LASitem::BYTE:
2828     case LASitem::BYTE14:
2829       laszip_dll->point.num_extra_bytes = laszip->items[i].size;
2830       if (laszip_dll->point.extra_bytes) delete [] laszip_dll->point.extra_bytes;
2831       laszip_dll->point.extra_bytes = new U8[laszip_dll->point.num_extra_bytes];
2832       laszip_dll->point_items[i] = laszip_dll->point.extra_bytes;
2833       break;
2834     case LASitem::WAVEPACKET13:
2835     case LASitem::WAVEPACKET14:
2836       laszip_dll->point_items[i] = (U8*)&(laszip_dll->point.wave_packet);
2837       break;
2838     default:
2839       sprintf(laszip_dll->error, "unknown LASitem type %d", (I32)laszip->items[i].type);
2840       return 1;
2841     }
2842   }
2843 
2844   if (compress)
2845   {
2846     if ((point_type > 5) && laszip_dll->request_native_extension)
2847     {
2848       if (!laszip->setup(point_type, point_size, LASZIP_COMPRESSOR_LAYERED_CHUNKED))
2849       {
2850         sprintf(laszip_dll->error, "cannot compress point_type %d with point_size %d using native", (I32)point_type, (I32)point_size);
2851         return 1;
2852       }
2853     }
2854     else
2855     {
2856       if (!laszip->setup(point_type, point_size, LASZIP_COMPRESSOR_DEFAULT))
2857       {
2858         sprintf(laszip_dll->error, "cannot compress point_type %d with point_size %d", (I32)point_type, (I32)point_size);
2859         return 1;
2860       }
2861     }
2862 
2863     // request version (old point types only, new point types always use version 3)
2864 
2865     laszip->request_version(2);
2866 
2867     // maybe we should change the chunk size
2868 
2869     if (laszip_dll->set_chunk_size != LASZIP_CHUNK_SIZE_DEFAULT)
2870     {
2871       if (!laszip->set_chunk_size(laszip_dll->set_chunk_size))
2872       {
2873         sprintf(laszip_dll->error, "setting chunk size %d has failed", laszip_dll->set_chunk_size);
2874         return 1;
2875       }
2876     }
2877   }
2878   else
2879   {
2880     laszip->request_version(0);
2881   }
2882   return 0;
2883 }
2884 
2885 /*---------------------------------------------------------------------------*/
2886 LASZIP_API laszip_I32
laszip_open_writer(laszip_POINTER pointer,const laszip_CHAR * file_name,laszip_BOOL compress)2887 laszip_open_writer(
2888     laszip_POINTER                     pointer
2889     , const laszip_CHAR*               file_name
2890     , laszip_BOOL                      compress
2891 )
2892 {
2893   if (pointer == 0) return 1;
2894   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
2895 
2896   try
2897   {
2898     if (file_name == 0)
2899     {
2900       sprintf(laszip_dll->error, "laszip_CHAR pointer 'file_name' is zero");
2901       return 1;
2902     }
2903 
2904     if (laszip_dll->reader)
2905     {
2906       sprintf(laszip_dll->error, "reader is already open");
2907       return 1;
2908     }
2909 
2910     if (laszip_dll->writer)
2911     {
2912       sprintf(laszip_dll->error, "writer is already open");
2913       return 1;
2914     }
2915 
2916     // open the file
2917 
2918 #ifdef _MSC_VER
2919     wchar_t* utf16_file_name = UTF8toUTF16(file_name);
2920     laszip_dll->file = _wfopen(utf16_file_name, L"wb");
2921     delete [] utf16_file_name;
2922 #else
2923 	laszip_dll->file = fopen(file_name, "wb");
2924 #endif
2925 
2926     if (laszip_dll->file == 0)
2927     {
2928       sprintf(laszip_dll->error, "cannot open file '%s'", file_name);
2929       return 1;
2930     }
2931 
2932     if (setvbuf(laszip_dll->file, NULL, _IOFBF, 262144) != 0)
2933     {
2934       sprintf(laszip_dll->warning, "setvbuf() failed with buffer size 262144\n");
2935     }
2936 
2937     // create the outstream
2938 
2939     if (IS_LITTLE_ENDIAN())
2940       laszip_dll->streamout = new ByteStreamOutFileLE(laszip_dll->file);
2941     else
2942       laszip_dll->streamout = new ByteStreamOutFileBE(laszip_dll->file);
2943 
2944     if (laszip_dll->streamout == 0)
2945     {
2946       sprintf(laszip_dll->error, "could not alloc ByteStreamOutFile");
2947       return 1;
2948     }
2949 
2950     // setup the items that make up the point
2951 
2952     LASzip laszip;
2953     if (setup_laszip_items(laszip_dll, &laszip, compress))
2954     {
2955       return 1;
2956     }
2957 
2958     // prepare header
2959 
2960     if (laszip_prepare_header_for_write(laszip_dll))
2961     {
2962       return 1;
2963     }
2964 
2965     // prepare point
2966 
2967     if (laszip_prepare_point_for_write(laszip_dll, compress))
2968     {
2969       return 1;
2970     }
2971 
2972     // prepare VLRs
2973 
2974     if (laszip_prepare_vlrs_for_write(laszip_dll))
2975     {
2976       return 1;
2977     }
2978 
2979     // write header variable after variable
2980 
2981     if (laszip_write_header(laszip_dll, &laszip, compress))
2982     {
2983       return 1;
2984     }
2985 
2986     // create the point writer
2987 
2988     if (create_point_writer(laszip_dll, &laszip))
2989     {
2990       return 1;
2991     }
2992 
2993     if (laszip_dll->lax_create)
2994     {
2995 	    // create spatial indexing information using cell_size = 100.0f and threshold = 1000
2996 
2997 	    LASquadtree* lasquadtree = new LASquadtree;
2998 	    lasquadtree->setup(laszip_dll->header.min_x, laszip_dll->header.max_x, laszip_dll->header.min_y, laszip_dll->header.max_y, 100.0f);
2999 
3000 	    laszip_dll->lax_index = new LASindex;
3001 	    laszip_dll->lax_index->prepare(lasquadtree, 1000);
3002 
3003       // copy the file name for later
3004 
3005       laszip_dll->lax_file_name = LASCopyString(file_name);
3006     }
3007 
3008     // set the point number and point count
3009 
3010     laszip_dll->npoints = (laszip_dll->header.number_of_point_records ? laszip_dll->header.number_of_point_records : laszip_dll->header.extended_number_of_point_records);
3011     laszip_dll->p_count = 0;
3012   }
3013   catch (...)
3014   {
3015     sprintf(laszip_dll->error, "internal error in laszip_open_writer '%s'", file_name);
3016     return 1;
3017   }
3018 
3019   laszip_dll->error[0] = '\0';
3020   return 0;
3021 }
3022 
3023 /*---------------------------------------------------------------------------*/
3024 LASZIP_API laszip_I32
laszip_write_point(laszip_POINTER pointer)3025 laszip_write_point(
3026     laszip_POINTER                     pointer
3027 )
3028 {
3029   if (pointer == 0) return 1;
3030   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
3031 
3032   try
3033   {
3034     // temporary fix to avoid corrupt LAZ files
3035 
3036     if (laszip_dll->point.extended_point_type)
3037     {
3038       // make sure legacy flags and extended flags are identical
3039       if ((laszip_dll->point.extended_classification_flags & 0x7) != ((((U8*)&(laszip_dll->point.intensity))[3]) >> 5))
3040       {
3041         sprintf(laszip_dll->error, "legacy flags and extended flags are not identical");
3042         return 1;
3043       }
3044 
3045       // make sure legacy classification is zero or identical to extended classification
3046       if (laszip_dll->point.classification != 0)
3047       {
3048         if (laszip_dll->point.classification != laszip_dll->point.extended_classification)
3049         {
3050           sprintf(laszip_dll->error, "legacy classification %d and extended classification %d are not consistent", laszip_dll->point.classification, laszip_dll->point.extended_classification);
3051           return 1;
3052         }
3053       }
3054     }
3055 
3056     // special recoding of points (in compatibility mode only)
3057 
3058     if (laszip_dll->compatibility_mode)
3059     {
3060       I32 scan_angle_remainder;
3061       I32 number_of_returns_increment;
3062       I32 return_number_increment;
3063       I32 return_count_difference;
3064       I32 overlap_bit;
3065       I32 scanner_channel;
3066 
3067       // distill extended attributes
3068       struct laszip_point* point = &laszip_dll->point;
3069 
3070       point->scan_angle_rank = I8_CLAMP(I16_QUANTIZE(0.006f*point->extended_scan_angle));
3071       scan_angle_remainder = point->extended_scan_angle - I16_QUANTIZE(((F32)point->scan_angle_rank)/0.006f);
3072       if (point->extended_number_of_returns <= 7)
3073       {
3074         point->number_of_returns = point->extended_number_of_returns;
3075         if (point->extended_return_number <= 7)
3076         {
3077           point->return_number = point->extended_return_number;
3078         }
3079         else
3080         {
3081           point->return_number = 7;
3082         }
3083       }
3084       else
3085       {
3086         point->number_of_returns = 7;
3087         if (point->extended_return_number <= 4)
3088         {
3089           point->return_number = point->extended_return_number;
3090         }
3091         else
3092         {
3093           return_count_difference = point->extended_number_of_returns - point->extended_return_number;
3094           if (return_count_difference <= 0)
3095           {
3096             point->return_number = 7;
3097           }
3098           else if (return_count_difference >= 3)
3099           {
3100             point->return_number = 4;
3101           }
3102           else
3103           {
3104             point->return_number = 7 - return_count_difference;
3105           }
3106         }
3107       }
3108       return_number_increment = point->extended_return_number - point->return_number;
3109       number_of_returns_increment = point->extended_number_of_returns - point->number_of_returns;
3110       if (point->extended_classification > 31)
3111       {
3112         point->classification = 0;
3113       }
3114       else
3115       {
3116         point->extended_classification = 0;
3117       }
3118       scanner_channel = point->extended_scanner_channel;
3119       overlap_bit = (point->extended_classification_flags >> 3);
3120 
3121       // write distilled extended attributes into extra bytes
3122 
3123       *((I16*)(point->extra_bytes + laszip_dll->start_scan_angle)) = ((I16)scan_angle_remainder);
3124       point->extra_bytes[laszip_dll->start_extended_returns] = (U8)((return_number_increment << 4) | number_of_returns_increment);
3125       point->extra_bytes[laszip_dll->start_classification] = (U8)(point->extended_classification);
3126       point->extra_bytes[laszip_dll->start_flags_and_channel] = (U8)((scanner_channel << 1) | overlap_bit);
3127       if (laszip_dll->start_NIR_band != -1)
3128       {
3129         *((U16*)(point->extra_bytes + laszip_dll->start_NIR_band)) = point->rgb[3];
3130       }
3131     }
3132 
3133     // write the point
3134     if (!laszip_dll->writer->write(laszip_dll->point_items))
3135     {
3136 #ifdef _WIN32
3137       sprintf(laszip_dll->error, "writing point %I64d of %I64d total points", laszip_dll->p_count, laszip_dll->npoints);
3138 #else
3139       sprintf(laszip_dll->error, "writing point %lld of %lld total points", laszip_dll->p_count, laszip_dll->npoints);
3140 #endif
3141       return 1;
3142     }
3143 
3144     laszip_dll->p_count++;
3145   }
3146   catch (...)
3147   {
3148     sprintf(laszip_dll->error, "internal error in laszip_write_point");
3149     return 1;
3150   }
3151 
3152   laszip_dll->error[0] = '\0';
3153   return 0;
3154 }
3155 
3156 /*---------------------------------------------------------------------------*/
3157 LASZIP_API laszip_I32
laszip_write_indexed_point(laszip_POINTER pointer)3158 laszip_write_indexed_point(
3159     laszip_POINTER                     pointer
3160 )
3161 {
3162   if (pointer == 0) return 1;
3163   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
3164 
3165   try
3166   {
3167     // write the point
3168     if (!laszip_dll->writer->write(laszip_dll->point_items))
3169     {
3170 #ifdef _WIN32
3171       sprintf(laszip_dll->error, "writing point %I64d of %I64d total points", laszip_dll->p_count, laszip_dll->npoints);
3172 #else
3173       sprintf(laszip_dll->error, "writing point %lld of %lld total points", laszip_dll->p_count, laszip_dll->npoints);
3174 #endif
3175       return 1;
3176     }
3177     // index the point
3178     F64 x = laszip_dll->header.x_scale_factor*laszip_dll->point.X+laszip_dll->header.x_offset;
3179     F64 y = laszip_dll->header.y_scale_factor*laszip_dll->point.Y+laszip_dll->header.y_offset;
3180     laszip_dll->lax_index->add(x, y, (U32)laszip_dll->p_count);
3181     laszip_dll->p_count++;
3182   }
3183   catch (...)
3184   {
3185     sprintf(laszip_dll->error, "internal error in laszip_write_indexed_point");
3186     return 1;
3187   }
3188 
3189   laszip_dll->error[0] = '\0';
3190   return 0;
3191 }
3192 
3193 /*---------------------------------------------------------------------------*/
3194 LASZIP_API laszip_I32
laszip_update_inventory(laszip_POINTER pointer)3195 laszip_update_inventory(
3196     laszip_POINTER                     pointer
3197 )
3198 {
3199   if (pointer == 0) return 1;
3200   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
3201 
3202   try
3203   {
3204     if (laszip_dll->inventory == 0)
3205     {
3206       laszip_dll->inventory = new laszip_dll_inventory;
3207     }
3208 
3209     laszip_dll->inventory->add(&laszip_dll->point);
3210   }
3211   catch (...)
3212   {
3213     sprintf(laszip_dll->error, "internal error in laszip_update_inventory");
3214     return 1;
3215   }
3216 
3217   laszip_dll->error[0] = '\0';
3218   return 0;
3219 }
3220 
3221 /*---------------------------------------------------------------------------*/
3222 LASZIP_API laszip_I32
laszip_close_writer(laszip_POINTER pointer)3223 laszip_close_writer(
3224     laszip_POINTER                     pointer
3225 )
3226 {
3227   if (pointer == 0) return 1;
3228   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
3229 
3230   try
3231   {
3232     if (laszip_dll->writer == 0)
3233     {
3234       sprintf(laszip_dll->error, "closing writer before it was opened");
3235       return 1;
3236     }
3237 
3238     if (!laszip_dll->writer->done())
3239     {
3240       sprintf(laszip_dll->error, "done of LASwritePoint failed");
3241       return 1;
3242     }
3243 
3244     delete laszip_dll->writer;
3245     laszip_dll->writer = 0;
3246 
3247     delete [] laszip_dll->point_items;
3248     laszip_dll->point_items = 0;
3249 
3250     // maybe update the header
3251 
3252     if (laszip_dll->inventory)
3253     {
3254       if (laszip_dll->header.point_data_format <= 5) // only update legacy counters for old point types
3255       {
3256         laszip_dll->streamout->seek(107);
3257         if (!laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->inventory->number_of_point_records)))
3258         {
3259           sprintf(laszip_dll->error, "updating laszip_dll->inventory->number_of_point_records");
3260           return 1;
3261         }
3262         for (I32 i = 0; i < 5; i++)
3263         {
3264           if (!laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->inventory->number_of_points_by_return[i+1])))
3265           {
3266             sprintf(laszip_dll->error, "updating laszip_dll->inventory->number_of_points_by_return[%d]\n", i);
3267             return 1;
3268           }
3269         }
3270       }
3271       laszip_dll->streamout->seek(179);
3272       F64 value;
3273       value = laszip_dll->header.x_scale_factor*laszip_dll->inventory->max_X+laszip_dll->header.x_offset;
3274       if (!laszip_dll->streamout->put64bitsLE((const U8*)&value))
3275       {
3276         sprintf(laszip_dll->error, "updating laszip_dll->inventory->max_X");
3277         return 1;
3278       }
3279       value = laszip_dll->header.x_scale_factor*laszip_dll->inventory->min_X+laszip_dll->header.x_offset;
3280       if (!laszip_dll->streamout->put64bitsLE((const U8*)&value))
3281       {
3282         sprintf(laszip_dll->error, "updating laszip_dll->inventory->min_X");
3283         return 1;
3284       }
3285       value = laszip_dll->header.y_scale_factor*laszip_dll->inventory->max_Y+laszip_dll->header.y_offset;
3286       if (!laszip_dll->streamout->put64bitsLE((const U8*)&value))
3287       {
3288         sprintf(laszip_dll->error, "updating laszip_dll->inventory->max_Y");
3289         return 1;
3290       }
3291       value = laszip_dll->header.y_scale_factor*laszip_dll->inventory->min_Y+laszip_dll->header.y_offset;
3292       if (!laszip_dll->streamout->put64bitsLE((const U8*)&value))
3293       {
3294         sprintf(laszip_dll->error, "updating laszip_dll->inventory->min_Y");
3295         return 1;
3296       }
3297       value = laszip_dll->header.z_scale_factor*laszip_dll->inventory->max_Z+laszip_dll->header.z_offset;
3298       if (!laszip_dll->streamout->put64bitsLE((const U8*)&value))
3299       {
3300         sprintf(laszip_dll->error, "updating laszip_dll->inventory->max_Z");
3301         return 1;
3302       }
3303       value = laszip_dll->header.z_scale_factor*laszip_dll->inventory->min_Z+laszip_dll->header.z_offset;
3304       if (!laszip_dll->streamout->put64bitsLE((const U8*)&value))
3305       {
3306         sprintf(laszip_dll->error, "updating laszip_dll->inventory->min_Z");
3307         return 1;
3308       }
3309       if (laszip_dll->header.version_minor >= 4) // only update extended counters for LAS 1.4
3310       {
3311         laszip_dll->streamout->seek(247);
3312         I64 number = laszip_dll->inventory->number_of_point_records;
3313         if (!laszip_dll->streamout->put64bitsLE((const U8*)&number))
3314         {
3315           sprintf(laszip_dll->error, "updating laszip_dll->inventory->extended_number_of_point_records");
3316           return 1;
3317         }
3318         for (I32 i = 0; i < 15; i++)
3319         {
3320           number = laszip_dll->inventory->number_of_points_by_return[i+1];
3321           if (!laszip_dll->streamout->put64bitsLE((const U8*)&number))
3322           {
3323             sprintf(laszip_dll->error, "updating laszip_dll->inventory->extended_number_of_points_by_return[%d]\n", i);
3324             return 1;
3325           }
3326         }
3327       }
3328       laszip_dll->streamout->seekEnd();
3329 
3330       delete laszip_dll->inventory;
3331       laszip_dll->inventory = 0;
3332     }
3333 
3334     if (laszip_dll->lax_index)
3335     {
3336       laszip_dll->lax_index->complete(100000, -20, FALSE);
3337 
3338       if (!laszip_dll->lax_index->write(laszip_dll->lax_file_name))
3339       {
3340         sprintf(laszip_dll->error, "writing LAX file to '%s'", laszip_dll->lax_file_name);
3341         return 1;
3342       }
3343 
3344       free(laszip_dll->lax_file_name);
3345       laszip_dll->lax_file_name = 0;
3346 
3347       delete laszip_dll->lax_index;
3348       laszip_dll->lax_index = 0;
3349     }
3350 
3351     delete laszip_dll->streamout;
3352     laszip_dll->streamout = 0;
3353 
3354 	  if (laszip_dll->file)
3355     {
3356       fclose(laszip_dll->file);
3357       laszip_dll->file = 0;
3358     }
3359   }
3360   catch (...)
3361   {
3362     sprintf(laszip_dll->error, "internal error in laszip_writer_close");
3363     return 1;
3364   }
3365 
3366   laszip_dll->error[0] = '\0';
3367   return 0;
3368 }
3369 
3370 /*---------------------------------------------------------------------------*/
3371 LASZIP_API laszip_I32
laszip_exploit_spatial_index(laszip_POINTER pointer,const laszip_BOOL exploit)3372 laszip_exploit_spatial_index(
3373     laszip_POINTER                     pointer
3374     , const laszip_BOOL                exploit
3375 )
3376 {
3377   if (pointer == 0) return 1;
3378   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
3379 
3380   try
3381   {
3382     if (laszip_dll->reader)
3383     {
3384       sprintf(laszip_dll->error, "reader is already open");
3385       return 1;
3386     }
3387 
3388     if (laszip_dll->writer)
3389     {
3390       sprintf(laszip_dll->error, "writer is already open");
3391       return 1;
3392     }
3393 
3394     laszip_dll->lax_exploit = exploit;
3395   }
3396   catch (...)
3397   {
3398     sprintf(laszip_dll->error, "internal error in laszip_exploit_spatial_index");
3399     return 1;
3400   }
3401 
3402   laszip_dll->error[0] = '\0';
3403   return 0;
3404 }
3405 
3406 /*---------------------------------------------------------------------------*/
3407 LASZIP_API laszip_I32
laszip_decompress_selective(laszip_POINTER pointer,const laszip_U32 decompress_selective)3408 laszip_decompress_selective(
3409     laszip_POINTER                     pointer
3410     , const laszip_U32                 decompress_selective
3411 )
3412 {
3413   if (pointer == 0) return 1;
3414   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
3415 
3416   try
3417   {
3418     if (laszip_dll->reader)
3419     {
3420       sprintf(laszip_dll->error, "reader is already open");
3421       return 1;
3422     }
3423 
3424     if (laszip_dll->writer)
3425     {
3426       sprintf(laszip_dll->error, "writer is already open");
3427       return 1;
3428     }
3429 
3430     laszip_dll->las14_decompress_selective = decompress_selective;
3431   }
3432   catch (...)
3433   {
3434     sprintf(laszip_dll->error, "internal error in laszip_decompress_selective");
3435     return 1;
3436   }
3437 
3438   laszip_dll->error[0] = '\0';
3439   return 0;
3440 }
3441 
3442 /*---------------------------------------------------------------------------*/
3443 static I32
laszip_read_header(laszip_dll_struct * laszip_dll,laszip_BOOL * is_compressed)3444 laszip_read_header(
3445     laszip_dll_struct*                 laszip_dll
3446     , laszip_BOOL*                     is_compressed
3447 )
3448 {
3449   U32 i;
3450 
3451   // read the header variable after variable
3452 
3453   CHAR file_signature[5];
3454   try { laszip_dll->streamin->getBytes((U8*)file_signature, 4); } catch(...)
3455   {
3456     sprintf(laszip_dll->error, "reading header.file_signature");
3457     return 1;
3458   }
3459   if (strncmp(file_signature, "LASF", 4) != 0)
3460   {
3461     sprintf(laszip_dll->error, "wrong file_signature. not a LAS/LAZ file.");
3462     return 1;
3463   }
3464   try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.file_source_ID)); } catch(...)
3465   {
3466     sprintf(laszip_dll->error, "reading header.file_source_ID");
3467     return 1;
3468   }
3469   try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.global_encoding)); } catch(...)
3470   {
3471     sprintf(laszip_dll->error, "reading header.global_encoding");
3472     return 1;
3473   }
3474   try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip_dll->header.project_ID_GUID_data_1)); } catch(...)
3475   {
3476     sprintf(laszip_dll->error, "reading header.project_ID_GUID_data_1");
3477     return 1;
3478   }
3479   try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.project_ID_GUID_data_2)); } catch(...)
3480   {
3481     sprintf(laszip_dll->error, "reading header.project_ID_GUID_data_2");
3482     return 1;
3483   }
3484   try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.project_ID_GUID_data_3)); } catch(...)
3485   {
3486     sprintf(laszip_dll->error, "reading header.project_ID_GUID_data_3");
3487     return 1;
3488   }
3489   try { laszip_dll->streamin->getBytes((U8*)laszip_dll->header.project_ID_GUID_data_4, 8); } catch(...)
3490   {
3491     sprintf(laszip_dll->error, "reading header.project_ID_GUID_data_4");
3492     return 1;
3493   }
3494   try { laszip_dll->streamin->getBytes((U8*)&(laszip_dll->header.version_major), 1); } catch(...)
3495   {
3496     sprintf(laszip_dll->error, "reading header.version_major");
3497     return 1;
3498   }
3499   try { laszip_dll->streamin->getBytes((U8*)&(laszip_dll->header.version_minor), 1); } catch(...)
3500   {
3501     sprintf(laszip_dll->error, "reading header.version_minor");
3502     return 1;
3503   }
3504   try { laszip_dll->streamin->getBytes((U8*)laszip_dll->header.system_identifier, 32); } catch(...)
3505   {
3506     sprintf(laszip_dll->error, "reading header.system_identifier");
3507     return 1;
3508   }
3509   try { laszip_dll->streamin->getBytes((U8*)laszip_dll->header.generating_software, 32); } catch(...)
3510   {
3511     sprintf(laszip_dll->error, "reading header.generating_software");
3512     return 1;
3513   }
3514   try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.file_creation_day)); } catch(...)
3515   {
3516     sprintf(laszip_dll->error, "reading header.file_creation_day");
3517     return 1;
3518   }
3519   try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.file_creation_year)); } catch(...)
3520   {
3521     sprintf(laszip_dll->error, "reading header.file_creation_year");
3522     return 1;
3523   }
3524   try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.header_size)); } catch(...)
3525   {
3526     sprintf(laszip_dll->error, "reading header.header_size");
3527     return 1;
3528   }
3529   try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip_dll->header.offset_to_point_data)); } catch(...)
3530   {
3531     sprintf(laszip_dll->error, "reading header.offset_to_point_data");
3532     return 1;
3533   }
3534   try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip_dll->header.number_of_variable_length_records)); } catch(...)
3535   {
3536     sprintf(laszip_dll->error, "reading header.number_of_variable_length_records");
3537     return 1;
3538   }
3539   try { laszip_dll->streamin->getBytes((U8*)&(laszip_dll->header.point_data_format), 1); } catch(...)
3540   {
3541     sprintf(laszip_dll->error, "reading header.point_data_format");
3542     return 1;
3543   }
3544   try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.point_data_record_length)); } catch(...)
3545   {
3546     sprintf(laszip_dll->error, "reading header.point_data_record_length");
3547     return 1;
3548   }
3549   try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip_dll->header.number_of_point_records)); } catch(...)
3550   {
3551     sprintf(laszip_dll->error, "reading header.number_of_point_records");
3552     return 1;
3553   }
3554   for (i = 0; i < 5; i++)
3555   {
3556     try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip_dll->header.number_of_points_by_return[i])); } catch(...)
3557     {
3558       sprintf(laszip_dll->error, "reading header.number_of_points_by_return %d", i);
3559       return 1;
3560     }
3561   }
3562   try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.x_scale_factor)); } catch(...)
3563   {
3564     sprintf(laszip_dll->error, "reading header.x_scale_factor");
3565     return 1;
3566   }
3567   try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.y_scale_factor)); } catch(...)
3568   {
3569     sprintf(laszip_dll->error, "reading header.y_scale_factor");
3570     return 1;
3571   }
3572   try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.z_scale_factor)); } catch(...)
3573   {
3574     sprintf(laszip_dll->error, "reading header.z_scale_factor");
3575     return 1;
3576   }
3577   try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.x_offset)); } catch(...)
3578   {
3579     sprintf(laszip_dll->error, "reading header.x_offset");
3580     return 1;
3581   }
3582   try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.y_offset)); } catch(...)
3583   {
3584     sprintf(laszip_dll->error, "reading header.y_offset");
3585     return 1;
3586   }
3587   try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.z_offset)); } catch(...)
3588   {
3589     sprintf(laszip_dll->error, "reading header.z_offset");
3590     return 1;
3591   }
3592   try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.max_x)); } catch(...)
3593   {
3594     sprintf(laszip_dll->error, "reading header.max_x");
3595     return 1;
3596   }
3597   try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.min_x)); } catch(...)
3598   {
3599     sprintf(laszip_dll->error, "reading header.min_x");
3600     return 1;
3601   }
3602   try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.max_y)); } catch(...)
3603   {
3604     sprintf(laszip_dll->error, "reading header.max_y");
3605     return 1;
3606   }
3607   try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.min_y)); } catch(...)
3608   {
3609     sprintf(laszip_dll->error, "reading header.min_y");
3610     return 1;
3611   }
3612   try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.max_z)); } catch(...)
3613   {
3614     sprintf(laszip_dll->error, "reading header.max_z");
3615     return 1;
3616   }
3617   try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.min_z)); } catch(...)
3618   {
3619     sprintf(laszip_dll->error, "reading header.min_z");
3620     return 1;
3621   }
3622 
3623   // special handling for LAS 1.3
3624   if ((laszip_dll->header.version_major == 1) && (laszip_dll->header.version_minor >= 3))
3625   {
3626     if (laszip_dll->header.header_size < 235)
3627     {
3628       sprintf(laszip_dll->error, "for LAS 1.%d header_size should at least be 235 but it is only %d", laszip_dll->header.version_minor, laszip_dll->header.header_size);
3629       return 1;
3630     }
3631     else
3632     {
3633       try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.start_of_waveform_data_packet_record)); } catch(...)
3634       {
3635         sprintf(laszip_dll->error, "reading header.start_of_waveform_data_packet_record");
3636         return 1;
3637       }
3638       laszip_dll->header.user_data_in_header_size = laszip_dll->header.header_size - 235;
3639     }
3640   }
3641   else
3642   {
3643     laszip_dll->header.user_data_in_header_size = laszip_dll->header.header_size - 227;
3644   }
3645 
3646   // special handling for LAS 1.4
3647   if ((laszip_dll->header.version_major == 1) && (laszip_dll->header.version_minor >= 4))
3648   {
3649     if (laszip_dll->header.header_size < 375)
3650     {
3651       sprintf(laszip_dll->error, "for LAS 1.%d header_size should at least be 375 but it is only %d", laszip_dll->header.version_minor, laszip_dll->header.header_size);
3652       return 1;
3653     }
3654     else
3655     {
3656       try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.start_of_first_extended_variable_length_record)); } catch(...)
3657       {
3658         sprintf(laszip_dll->error, "reading header.start_of_first_extended_variable_length_record");
3659         return 1;
3660       }
3661       try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip_dll->header.number_of_extended_variable_length_records)); } catch(...)
3662       {
3663         sprintf(laszip_dll->error, "reading header.number_of_extended_variable_length_records");
3664         return 1;
3665       }
3666       try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.extended_number_of_point_records)); } catch(...)
3667       {
3668         sprintf(laszip_dll->error, "reading header.extended_number_of_point_records");
3669         return 1;
3670       }
3671       for (i = 0; i < 15; i++)
3672       {
3673         try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.extended_number_of_points_by_return[i])); } catch(...)
3674         {
3675           sprintf(laszip_dll->error, "reading header.extended_number_of_points_by_return[%d]", i);
3676           return 1;
3677         }
3678       }
3679       laszip_dll->header.user_data_in_header_size = laszip_dll->header.header_size - 375;
3680     }
3681   }
3682 
3683   // load any number of user-defined bytes that might have been added to the header
3684   if (laszip_dll->header.user_data_in_header_size)
3685   {
3686     if (laszip_dll->header.user_data_in_header)
3687     {
3688       delete [] laszip_dll->header.user_data_in_header;
3689     }
3690     laszip_dll->header.user_data_in_header = new U8[laszip_dll->header.user_data_in_header_size];
3691 
3692     try { laszip_dll->streamin->getBytes((U8*)laszip_dll->header.user_data_in_header, laszip_dll->header.user_data_in_header_size); } catch(...)
3693     {
3694       sprintf(laszip_dll->error, "reading %u bytes of data into header.user_data_in_header", laszip_dll->header.user_data_in_header_size);
3695       return 1;
3696     }
3697   }
3698 
3699   // read variable length records into the header
3700 
3701   U32 vlrs_size = 0;
3702   LASzip* laszip = 0;
3703 
3704   if (laszip_dll->header.number_of_variable_length_records)
3705   {
3706     U32 i;
3707 
3708     laszip_dll->header.vlrs = (laszip_vlr*)malloc(sizeof(laszip_vlr)*laszip_dll->header.number_of_variable_length_records);
3709 
3710     if (laszip_dll->header.vlrs == 0)
3711     {
3712       sprintf(laszip_dll->error, "allocating %u VLRs", laszip_dll->header.number_of_variable_length_records);
3713       return 1;
3714     }
3715 
3716     for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
3717     {
3718       // make sure there are enough bytes left to read a variable length record before the point block starts
3719 
3720       if (((int)laszip_dll->header.offset_to_point_data - vlrs_size - laszip_dll->header.header_size) < 54)
3721       {
3722         sprintf(laszip_dll->warning, "only %d bytes until point block after reading %d of %d vlrs. skipping remaining vlrs ...", (int)laszip_dll->header.offset_to_point_data - vlrs_size - laszip_dll->header.header_size, i, laszip_dll->header.number_of_variable_length_records);
3723         laszip_dll->header.number_of_variable_length_records = i;
3724         break;
3725       }
3726 
3727       // read variable length records variable after variable (to avoid alignment issues)
3728 
3729       try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.vlrs[i].reserved)); } catch(...)
3730       {
3731         sprintf(laszip_dll->error, "reading header.vlrs[%u].reserved", i);
3732         return 1;
3733       }
3734 
3735       try { laszip_dll->streamin->getBytes((U8*)laszip_dll->header.vlrs[i].user_id, 16); } catch(...)
3736       {
3737         sprintf(laszip_dll->error, "reading header.vlrs[%u].user_id", i);
3738         return 1;
3739       }
3740       try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.vlrs[i].record_id)); } catch(...)
3741       {
3742         sprintf(laszip_dll->error, "reading header.vlrs[%u].record_id", i);
3743         return 1;
3744       }
3745       try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.vlrs[i].record_length_after_header)); } catch(...)
3746       {
3747         sprintf(laszip_dll->error, "reading header.vlrs[%u].record_length_after_header", i);
3748         return 1;
3749       }
3750       try { laszip_dll->streamin->getBytes((U8*)laszip_dll->header.vlrs[i].description, 32); } catch(...)
3751       {
3752         sprintf(laszip_dll->error, "reading header.vlrs[%u].description", i);
3753         return 1;
3754       }
3755 
3756       // keep track on the number of bytes we have read so far
3757 
3758       vlrs_size += 54;
3759 
3760       // check variable length record contents
3761 
3762       if ((laszip_dll->header.vlrs[i].reserved != 0xAABB) && (laszip_dll->header.vlrs[i].reserved != 0x0))
3763       {
3764         sprintf(laszip_dll->warning,"wrong header.vlrs[%d].reserved: %d != 0xAABB and %d != 0x0", i, laszip_dll->header.vlrs[i].reserved, laszip_dll->header.vlrs[i].reserved);
3765       }
3766 
3767       // make sure there are enough bytes left to read the data of the variable length record before the point block starts
3768 
3769       if (((int)laszip_dll->header.offset_to_point_data - vlrs_size - laszip_dll->header.header_size) < laszip_dll->header.vlrs[i].record_length_after_header)
3770       {
3771         sprintf(laszip_dll->warning, "only %d bytes until point block when trying to read %d bytes into header.vlrs[%d].data", (int)laszip_dll->header.offset_to_point_data - vlrs_size - laszip_dll->header.header_size, laszip_dll->header.vlrs[i].record_length_after_header, i);
3772         laszip_dll->header.vlrs[i].record_length_after_header = (int)laszip_dll->header.offset_to_point_data - vlrs_size - laszip_dll->header.header_size;
3773       }
3774 
3775       // load data following the header of the variable length record
3776 
3777       if (laszip_dll->header.vlrs[i].record_length_after_header)
3778       {
3779         if ((strcmp(laszip_dll->header.vlrs[i].user_id, "laszip encoded") == 0) && (laszip_dll->header.vlrs[i].record_id == 22204))
3780         {
3781           if (laszip)
3782           {
3783             delete laszip;
3784           }
3785 
3786           laszip = new LASzip();
3787 
3788           if (laszip == 0)
3789           {
3790             sprintf(laszip_dll->error, "could not alloc LASzip");
3791             return 1;
3792           }
3793 
3794           // read the LASzip VLR payload
3795 
3796           //     U16  compressor                2 bytes
3797           //     U32  coder                     2 bytes
3798           //     U8   version_major             1 byte
3799           //     U8   version_minor             1 byte
3800           //     U16  version_revision          2 bytes
3801           //     U32  options                   4 bytes
3802           //     I32  chunk_size                4 bytes
3803           //     I64  number_of_special_evlrs   8 bytes
3804           //     I64  offset_to_special_evlrs   8 bytes
3805           //     U16  num_items                 2 bytes
3806           //        U16 type                2 bytes * num_items
3807           //        U16 size                2 bytes * num_items
3808           //        U16 version             2 bytes * num_items
3809           // which totals 34+6*num_items
3810 
3811           try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip->compressor)); } catch(...)
3812           {
3813             sprintf(laszip_dll->error, "reading compressor %d", (I32)laszip->compressor);
3814             return 1;
3815           }
3816           try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip->coder)); } catch(...)
3817           {
3818             sprintf(laszip_dll->error, "reading coder %d", (I32)laszip->coder);
3819             return 1;
3820           }
3821           try { laszip_dll->streamin->getBytes((U8*)&(laszip->version_major), 1); } catch(...)
3822           {
3823             sprintf(laszip_dll->error, "reading version_major %d", (I32)laszip->version_major);
3824             return 1;
3825           }
3826           try { laszip_dll->streamin->getBytes((U8*)&(laszip->version_minor), 1); } catch(...)
3827           {
3828             sprintf(laszip_dll->error, "reading version_minor %d", (I32)laszip->version_minor);
3829             return 1;
3830           }
3831           try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip->version_revision)); } catch(...)
3832           {
3833             sprintf(laszip_dll->error, "reading version_revision %d", (I32)laszip->version_revision);
3834             return 1;
3835           }
3836           try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip->options)); } catch(...)
3837           {
3838             sprintf(laszip_dll->error, "reading options %u", laszip->options);
3839             return 1;
3840           }
3841           try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip->chunk_size)); } catch(...)
3842           {
3843             sprintf(laszip_dll->error, "reading chunk_size %u", laszip->chunk_size);
3844             return 1;
3845           }
3846           try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip->number_of_special_evlrs)); } catch(...)
3847           {
3848             sprintf(laszip_dll->error, "reading number_of_special_evlrs %d", (I32)laszip->number_of_special_evlrs);
3849             return 1;
3850           }
3851           try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip->offset_to_special_evlrs)); } catch(...)
3852           {
3853             sprintf(laszip_dll->error, "reading offset_to_special_evlrs %d", (I32)laszip->offset_to_special_evlrs);
3854             return 1;
3855           }
3856           try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip->num_items)); } catch(...)
3857           {
3858             sprintf(laszip_dll->error, "reading num_items %d", (I32)laszip->num_items);
3859             return 1;
3860           }
3861           laszip->items = new LASitem[laszip->num_items];
3862           U32 j;
3863           for (j = 0; j < laszip->num_items; j++)
3864           {
3865             U16 type;
3866             try { laszip_dll->streamin->get16bitsLE((U8*)&type); } catch(...)
3867             {
3868               sprintf(laszip_dll->error, "reading type of item %u", j);
3869               return 1;
3870             }
3871             laszip->items[j].type = (LASitem::Type)type;
3872             try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip->items[j].size)); } catch(...)
3873             {
3874               sprintf(laszip_dll->error, "reading size of item %u", j);
3875               return 1;
3876             }
3877             try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip->items[j].version)); } catch(...)
3878             {
3879               sprintf(laszip_dll->error, "reading version of item %u", j);
3880               return 1;
3881             }
3882           }
3883         }
3884         else
3885         {
3886           laszip_dll->header.vlrs[i].data = new U8[laszip_dll->header.vlrs[i].record_length_after_header];
3887 
3888           try { laszip_dll->streamin->getBytes(laszip_dll->header.vlrs[i].data, laszip_dll->header.vlrs[i].record_length_after_header); } catch(...)
3889           {
3890             sprintf(laszip_dll->error, "reading %d bytes of data into header.vlrs[%u].data", (I32)laszip_dll->header.vlrs[i].record_length_after_header, i);
3891             return 1;
3892           }
3893         }
3894       }
3895       else
3896       {
3897         laszip_dll->header.vlrs[i].data = 0;
3898       }
3899 
3900       // keep track on the number of bytes we have read so far
3901 
3902       vlrs_size += laszip_dll->header.vlrs[i].record_length_after_header;
3903 
3904       // special handling for LASzip VLR
3905 
3906       if ((strcmp(laszip_dll->header.vlrs[i].user_id, "laszip encoded") == 0) && (laszip_dll->header.vlrs[i].record_id == 22204))
3907       {
3908         // we take our the VLR for LASzip away
3909         laszip_dll->header.offset_to_point_data -= (54+laszip_dll->header.vlrs[i].record_length_after_header);
3910         vlrs_size -= (54+laszip_dll->header.vlrs[i].record_length_after_header);
3911         i--;
3912         laszip_dll->header.number_of_variable_length_records--;
3913         // free or resize the VLR array
3914         if (laszip_dll->header.number_of_variable_length_records == 0)
3915         {
3916           free(laszip_dll->header.vlrs);
3917           laszip_dll->header.vlrs = 0;
3918         }
3919         else
3920         {
3921           laszip_dll->header.vlrs = (laszip_vlr*)realloc(laszip_dll->header.vlrs, sizeof(laszip_vlr)*laszip_dll->header.number_of_variable_length_records);
3922         }
3923       }
3924     }
3925   }
3926 
3927   // load any number of user-defined bytes that might have been added after the header
3928 
3929   laszip_dll->header.user_data_after_header_size = (I32)laszip_dll->header.offset_to_point_data - vlrs_size - laszip_dll->header.header_size;
3930   if (laszip_dll->header.user_data_after_header_size)
3931   {
3932     if (laszip_dll->header.user_data_after_header)
3933     {
3934       delete [] laszip_dll->header.user_data_after_header;
3935     }
3936     laszip_dll->header.user_data_after_header = new U8[laszip_dll->header.user_data_after_header_size];
3937 
3938     try { laszip_dll->streamin->getBytes((U8*)laszip_dll->header.user_data_after_header, laszip_dll->header.user_data_after_header_size); } catch(...)
3939     {
3940       sprintf(laszip_dll->error, "reading %u bytes of data into header.user_data_after_header", laszip_dll->header.user_data_after_header_size);
3941       return 1;
3942     }
3943   }
3944 
3945   // remove extra bits in point data type
3946 
3947   if ((laszip_dll->header.point_data_format & 128) || (laszip_dll->header.point_data_format & 64))
3948   {
3949     if (!laszip)
3950     {
3951       sprintf(laszip_dll->error, "this file was compressed with an experimental version of LASzip. contact 'martin.isenburg@rapidlasso.com' for assistance");
3952       return 1;
3953     }
3954     laszip_dll->header.point_data_format &= 127;
3955   }
3956 
3957   // check if file is compressed
3958 
3959   if (laszip)
3960   {
3961     // yes. check the compressor state
3962     *is_compressed = 1;
3963     if (!laszip->check(laszip_dll->header.point_data_record_length))
3964     {
3965       sprintf(laszip_dll->error, "%s upgrade to the latest release of LASzip or contact 'martin.isenburg@rapidlasso.com' for assistance", laszip->get_error());
3966       return 1;
3967     }
3968   }
3969   else
3970   {
3971     // no. setup an un-compressed read
3972     *is_compressed = 0;
3973     laszip = new LASzip;
3974     if (laszip == 0)
3975     {
3976       sprintf(laszip_dll->error, "could not alloc LASzip");
3977       return 1;
3978     }
3979     if (!laszip->setup(laszip_dll->header.point_data_format, laszip_dll->header.point_data_record_length, LASZIP_COMPRESSOR_NONE))
3980     {
3981       sprintf(laszip_dll->error, "invalid combination of point_data_format %d and point_data_record_length %d", (I32)laszip_dll->header.point_data_format, (I32)laszip_dll->header.point_data_record_length);
3982       return 1;
3983     }
3984   }
3985 
3986   // create point's item pointers
3987 
3988   if (laszip_dll->point_items)
3989   {
3990     delete [] laszip_dll->point_items;
3991   }
3992 
3993   laszip_dll->point_items = new U8*[laszip->num_items];
3994 
3995   if (laszip_dll->point_items == 0)
3996   {
3997     sprintf(laszip_dll->error, "could not alloc point_items");
3998     return 1;
3999   }
4000 
4001   for (i = 0; i < laszip->num_items; i++)
4002   {
4003     switch (laszip->items[i].type)
4004     {
4005     case LASitem::POINT10:
4006     case LASitem::POINT14:
4007       laszip_dll->point_items[i] = (U8*)&(laszip_dll->point.X);
4008       break;
4009     case LASitem::GPSTIME11:
4010       laszip_dll->point_items[i] = (U8*)&(laszip_dll->point.gps_time);
4011       break;
4012     case LASitem::RGB12:
4013     case LASitem::RGB14:
4014     case LASitem::RGBNIR14:
4015       laszip_dll->point_items[i] = (U8*)laszip_dll->point.rgb;
4016       break;
4017     case LASitem::BYTE:
4018     case LASitem::BYTE14:
4019       laszip_dll->point.num_extra_bytes = laszip->items[i].size;
4020       if (laszip_dll->point.extra_bytes) delete [] laszip_dll->point.extra_bytes;
4021       laszip_dll->point.extra_bytes = new U8[laszip_dll->point.num_extra_bytes];
4022       laszip_dll->point_items[i] = laszip_dll->point.extra_bytes;
4023       break;
4024     case LASitem::WAVEPACKET13:
4025     case LASitem::WAVEPACKET14:
4026       laszip_dll->point_items[i] = (U8*)&(laszip_dll->point.wave_packet);
4027       break;
4028     default:
4029       sprintf(laszip_dll->error, "unknown LASitem type %d", (I32)laszip->items[i].type);
4030       return 1;
4031     }
4032   }
4033 
4034   // did the user request to recode the compatibility mode points?
4035 
4036   laszip_dll->compatibility_mode = FALSE;
4037 
4038   if (laszip_dll->request_compatibility_mode && (laszip_dll->header.version_minor < 4))
4039   {
4040     // does this file contain compatibility mode recoded LAS 1.4 content
4041 
4042     struct laszip_vlr* compatibility_VLR = 0;
4043 
4044     if (laszip_dll->header.point_data_format == 1 || laszip_dll->header.point_data_format == 3 || laszip_dll->header.point_data_format == 4 || laszip_dll->header.point_data_format == 5)
4045     {
4046       // if we find the compatibility VLR
4047 
4048       for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
4049       {
4050         if ((strncmp(laszip_dll->header.vlrs[i].user_id, "lascompatible\0\0", 16) == 0) && (laszip_dll->header.vlrs[i].record_id == 22204))
4051         {
4052           if (laszip_dll->header.vlrs[i].record_length_after_header == 2+2+4+148)
4053           {
4054             compatibility_VLR = &(laszip_dll->header.vlrs[i]);
4055             break;
4056           }
4057         }
4058       }
4059 
4060       if (compatibility_VLR)
4061       {
4062         // and we also find the extra bytes VLR with the right attributes
4063 
4064         LASattributer attributer;
4065         for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
4066         {
4067           if ((strncmp(laszip_dll->header.vlrs[i].user_id, "LASF_Spec\0\0\0\0\0\0", 16) == 0) && (laszip_dll->header.vlrs[i].record_id == 4))
4068           {
4069             attributer.init_attributes(laszip_dll->header.vlrs[i].record_length_after_header/192, (LASattribute*)laszip_dll->header.vlrs[i].data);
4070             laszip_dll->start_scan_angle = attributer.get_attribute_start("LAS 1.4 scan angle");
4071             laszip_dll->start_extended_returns = attributer.get_attribute_start("LAS 1.4 extended returns");
4072             laszip_dll->start_classification = attributer.get_attribute_start("LAS 1.4 classification");
4073             laszip_dll->start_flags_and_channel = attributer.get_attribute_start("LAS 1.4 flags and channel");
4074             laszip_dll->start_NIR_band = attributer.get_attribute_start("LAS 1.4 NIR band");
4075             break;
4076           }
4077         }
4078 
4079         // can we do it ... ?
4080 
4081         if ((laszip_dll->start_scan_angle != -1) && (laszip_dll->start_extended_returns != -1) && (laszip_dll->start_classification != -1) && (laszip_dll->start_flags_and_channel != -1))
4082         {
4083           // yes ... so let's fix the header (using the content from the compatibility VLR)
4084 
4085           ByteStreamInArray* in;
4086           if (IS_LITTLE_ENDIAN())
4087             in = new ByteStreamInArrayLE(compatibility_VLR->data, compatibility_VLR->record_length_after_header);
4088           else
4089             in = new ByteStreamInArrayBE(compatibility_VLR->data, compatibility_VLR->record_length_after_header);
4090           // read control info
4091           U16 laszip_version;
4092           in->get16bitsLE((U8*)&laszip_version);
4093           U16 compatible_version;
4094           in->get16bitsLE((U8*)&compatible_version);
4095           U32 unused;
4096           in->get32bitsLE((U8*)&unused);
4097           // read the 148 bytes of the extended LAS 1.4 header
4098           U64 start_of_waveform_data_packet_record;
4099           in->get64bitsLE((U8*)&start_of_waveform_data_packet_record);
4100           if (start_of_waveform_data_packet_record != 0)
4101           {
4102 #ifdef _WIN32
4103             fprintf(stderr,"WARNING: start_of_waveform_data_packet_record is %I64d. reading 0 instead.\n", start_of_waveform_data_packet_record);
4104 #else
4105             fprintf(stderr,"WARNING: start_of_waveform_data_packet_record is %llu. reading 0 instead.\n", start_of_waveform_data_packet_record);
4106 #endif
4107           }
4108           laszip_dll->header.start_of_waveform_data_packet_record = 0;
4109           U64 start_of_first_extended_variable_length_record;
4110           in->get64bitsLE((U8*)&start_of_first_extended_variable_length_record);
4111           if (start_of_first_extended_variable_length_record != 0)
4112           {
4113 #ifdef _WIN32
4114             fprintf(stderr,"WARNING: EVLRs not supported. start_of_first_extended_variable_length_record is %I64d. reading 0 instead.\n", start_of_first_extended_variable_length_record);
4115 #else
4116             fprintf(stderr,"WARNING: EVLRs not supported. start_of_first_extended_variable_length_record is %llu. reading 0 instead.\n", start_of_first_extended_variable_length_record);
4117 #endif
4118           }
4119           laszip_dll->header.start_of_first_extended_variable_length_record = 0;
4120           U32 number_of_extended_variable_length_records ;
4121           in->get32bitsLE((U8*)&number_of_extended_variable_length_records);
4122           if (number_of_extended_variable_length_records != 0)
4123           {
4124             fprintf(stderr,"WARNING: EVLRs not supported. number_of_extended_variable_length_records is %u. reading 0 instead.\n", number_of_extended_variable_length_records);
4125           }
4126           laszip_dll->header.number_of_extended_variable_length_records = 0;
4127           U64 extended_number_of_point_records = 0;
4128           in->get64bitsLE((U8*)&extended_number_of_point_records);
4129           if (laszip_dll->header.number_of_point_records != 0 && ((U64)(laszip_dll->header.number_of_point_records)) != extended_number_of_point_records)
4130           {
4131 #ifdef _WIN32
4132             fprintf(stderr,"WARNING: number_of_point_records is %u. but extended_number_of_point_records is %I64u.\n", laszip_dll->header.number_of_point_records, extended_number_of_point_records);
4133 #else
4134             fprintf(stderr,"WARNING: number_of_point_records is %u. but extended_number_of_point_records is %llu.\n", laszip_dll->header.number_of_point_records, extended_number_of_point_records);
4135 #endif
4136           }
4137           laszip_dll->header.extended_number_of_point_records = extended_number_of_point_records;
4138           U64 extended_number_of_points_by_return;
4139           for (U32 r = 0; r < 15; r++)
4140           {
4141             in->get64bitsLE((U8*)&extended_number_of_points_by_return);
4142             if ((r < 5) && laszip_dll->header.number_of_points_by_return[r] != 0 && ((U64)(laszip_dll->header.number_of_points_by_return[r])) != extended_number_of_points_by_return)
4143             {
4144 #ifdef _WIN32
4145               fprintf(stderr,"WARNING: number_of_points_by_return[%u] is %u. but extended_number_of_points_by_return[%u] is %I64u.\n", r, laszip_dll->header.number_of_points_by_return[r], r, extended_number_of_points_by_return);
4146 #else
4147               fprintf(stderr,"WARNING: number_of_points_by_return[%u] is %u. but extended_number_of_points_by_return[%u] is %llu.\n", r, laszip_dll->header.number_of_points_by_return[r], r, extended_number_of_points_by_return);
4148 #endif
4149             }
4150             laszip_dll->header.extended_number_of_points_by_return[r] = extended_number_of_points_by_return;
4151           }
4152           delete in;
4153 
4154           // remove the compatibility VLR
4155 
4156           if (laszip_remove_vlr(laszip_dll, "lascompatible\0\0", 22204))
4157           {
4158             sprintf(laszip_dll->error, "removing the compatibility VLR");
4159             return 1;
4160           }
4161 
4162           // remove the LAS 1.4 attributes from the "extra bytes" description
4163 
4164           if (laszip_dll->start_NIR_band != -1) attributer.remove_attribute("LAS 1.4 NIR band");
4165           attributer.remove_attribute("LAS 1.4 flags and channel");
4166           attributer.remove_attribute("LAS 1.4 classification");
4167           attributer.remove_attribute("LAS 1.4 extended returns");
4168           attributer.remove_attribute("LAS 1.4 scan angle");
4169 
4170           // either rewrite or remove the "extra bytes" VLR
4171 
4172           if (attributer.number_attributes)
4173           {
4174             if (laszip_add_vlr(laszip_dll, "LASF_Spec\0\0\0\0\0\0", 4, (laszip_U16)(attributer.number_attributes*sizeof(LASattribute)), 0, (laszip_U8*)attributer.attributes))
4175             {
4176               sprintf(laszip_dll->error, "rewriting the extra bytes VLR without 'LAS 1.4 compatibility mode' attributes");
4177               return 1;
4178             }
4179           }
4180           else
4181           {
4182             if (laszip_remove_vlr(laszip_dll, "LASF_Spec\0\0\0\0\0\0", 4))
4183             {
4184               sprintf(laszip_dll->error, "removing the LAS 1.4 attribute VLR");
4185               return 1;
4186             }
4187           }
4188 
4189           // upgrade to LAS 1.4
4190           if (laszip_dll->header.version_minor < 3)
4191           {
4192             // LAS 1.2 header is 148 bytes less than LAS 1.4+ header
4193             laszip_dll->header.header_size += 148;
4194             laszip_dll->header.offset_to_point_data += 148;
4195           }
4196           else
4197           {
4198             // LAS 1.3 header is 140 bytes less than LAS 1.4+ header
4199             laszip_dll->header.header_size += 140;
4200             laszip_dll->header.offset_to_point_data += 140;
4201           }
4202           laszip_dll->header.version_minor = 4;
4203 
4204           // maybe turn on the bit indicating the presence of the OGC WKT
4205           for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
4206           {
4207             if ((strncmp(laszip_dll->header.vlrs[i].user_id, "LASF_Projection", 16) == 0) && (laszip_dll->header.vlrs[i].record_id == 2112))
4208             {
4209               laszip_dll->header.global_encoding |= (1<<4);
4210               break;
4211             }
4212           }
4213 
4214           // update point type and size
4215 
4216           laszip_dll->point.extended_point_type = 1;
4217 
4218           if (laszip_dll->header.point_data_format == 1)
4219           {
4220             laszip_dll->header.point_data_format = 6;
4221             laszip_dll->header.point_data_record_length += (2 - 5); // record is 2 bytes larger but minus 5 extra bytes
4222           }
4223           else if (laszip_dll->header.point_data_format == 3)
4224           {
4225             if (laszip_dll->start_NIR_band == -1)
4226             {
4227               laszip_dll->header.point_data_format = 7;
4228               laszip_dll->header.point_data_record_length += (2 - 5); // record is 2 bytes larger but minus 5 extra bytes
4229             }
4230             else
4231             {
4232               laszip_dll->header.point_data_format = 8;
4233               laszip_dll->header.point_data_record_length += (4 - 7); // record is 4 bytes larger but minus 7 extra bytes
4234             }
4235           }
4236           else
4237           {
4238             if (laszip_dll->start_NIR_band == -1)
4239             {
4240               laszip_dll->header.point_data_format = 9;
4241               laszip_dll->header.point_data_record_length += (2 - 5);
4242             }
4243             else
4244             {
4245               laszip_dll->header.point_data_format = 10;
4246               laszip_dll->header.point_data_record_length += (4 - 7);
4247             }
4248           }
4249 
4250           // we are operating in compatibility mode
4251 
4252           laszip_dll->compatibility_mode = TRUE;
4253         }
4254       }
4255     }
4256   }
4257   else if (laszip_dll->header.point_data_format > 5)
4258   {
4259     laszip_dll->point.extended_point_type = 1;
4260   }
4261 
4262   // create the point reader
4263 
4264   laszip_dll->reader = new LASreadPoint(laszip_dll->las14_decompress_selective);
4265   if (laszip_dll->reader == 0)
4266   {
4267     sprintf(laszip_dll->error, "could not alloc LASreadPoint");
4268     return 1;
4269   }
4270 
4271   if (!laszip_dll->reader->setup(laszip->num_items, laszip->items, laszip))
4272   {
4273     sprintf(laszip_dll->error, "setup of LASreadPoint failed");
4274     return 1;
4275   }
4276 
4277   if (!laszip_dll->reader->init(laszip_dll->streamin))
4278   {
4279     sprintf(laszip_dll->error, "init of LASreadPoint failed");
4280     return 1;
4281   }
4282 
4283   delete laszip;
4284 
4285   // set the point number and point count
4286 
4287   laszip_dll->npoints = (laszip_dll->header.number_of_point_records ? laszip_dll->header.number_of_point_records : laszip_dll->header.extended_number_of_point_records);
4288   laszip_dll->p_count = 0;
4289 
4290   laszip_dll->error[0] = '\0';
4291   return 0;
4292 }
4293 
4294 /*---------------------------------------------------------------------------*/
4295 LASZIP_API laszip_I32
laszip_open_reader(laszip_POINTER pointer,const laszip_CHAR * file_name,laszip_BOOL * is_compressed)4296 laszip_open_reader(
4297     laszip_POINTER                     pointer
4298     , const laszip_CHAR*               file_name
4299     , laszip_BOOL*                     is_compressed
4300 )
4301 {
4302   if (pointer == 0) return 1;
4303   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
4304 
4305   try
4306   {
4307     if (file_name == 0)
4308     {
4309       sprintf(laszip_dll->error, "laszip_CHAR pointer 'file_name' is zero");
4310       return 1;
4311     }
4312 
4313     if (is_compressed == 0)
4314     {
4315       sprintf(laszip_dll->error, "laszip_BOOL pointer 'is_compressed' is zero");
4316       return 1;
4317     }
4318 
4319     if (laszip_dll->writer)
4320     {
4321       sprintf(laszip_dll->error, "writer is already open");
4322       return 1;
4323     }
4324 
4325     if (laszip_dll->reader)
4326     {
4327       sprintf(laszip_dll->error, "reader is already open");
4328       return 1;
4329     }
4330 
4331     // open the file
4332 
4333 #ifdef _MSC_VER
4334     wchar_t* utf16_file_name = UTF8toUTF16(file_name);
4335     laszip_dll->file = _wfopen(utf16_file_name, L"rb");
4336     delete [] utf16_file_name;
4337 #else
4338 	laszip_dll->file = fopen(file_name, "rb");
4339 #endif
4340 
4341     if (laszip_dll->file == 0)
4342     {
4343       sprintf(laszip_dll->error, "cannot open file '%s'", file_name);
4344       return 1;
4345     }
4346 
4347     if (setvbuf(laszip_dll->file, NULL, _IOFBF, 262144) != 0)
4348     {
4349       sprintf(laszip_dll->warning, "setvbuf() failed with buffer size 262144\n");
4350     }
4351 
4352     if (IS_LITTLE_ENDIAN())
4353       laszip_dll->streamin = new ByteStreamInFileLE(laszip_dll->file);
4354     else
4355       laszip_dll->streamin = new ByteStreamInFileBE(laszip_dll->file);
4356 
4357     if (laszip_dll->streamin == 0)
4358     {
4359       sprintf(laszip_dll->error, "could not alloc ByteStreamInFile");
4360       return 1;
4361     }
4362 
4363     // read the header variable after variable
4364 
4365     if (laszip_read_header(laszip_dll, is_compressed))
4366     {
4367       return 1;
4368     }
4369 
4370     // should we try to exploit existing spatial indexing information
4371 
4372     if (laszip_dll->lax_exploit)
4373     {
4374       laszip_dll->lax_index = new LASindex();
4375 
4376       if (!laszip_dll->lax_index->read(file_name))
4377       {
4378         delete laszip_dll->lax_index;
4379         laszip_dll->lax_index = 0;
4380       }
4381     }
4382   }
4383   catch (...)
4384   {
4385     sprintf(laszip_dll->error, "internal error in laszip_open_reader");
4386     return 1;
4387   }
4388 
4389   laszip_dll->error[0] = '\0';
4390   return 0;
4391 }
4392 
4393 /*---------------------------------------------------------------------------*/
4394 LASZIP_API laszip_I32
laszip_has_spatial_index(laszip_POINTER pointer,laszip_BOOL * is_indexed,laszip_BOOL * is_appended)4395 laszip_has_spatial_index(
4396     laszip_POINTER                     pointer
4397     , laszip_BOOL*                     is_indexed
4398     , laszip_BOOL*                     is_appended
4399 )
4400 {
4401   if (pointer == 0) return 1;
4402   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
4403 
4404   try
4405   {
4406     if (is_indexed == 0)
4407     {
4408       sprintf(laszip_dll->error, "laszip_BOOL pointer 'is_indexed' is zero");
4409       return 1;
4410     }
4411 
4412     if (laszip_dll->reader == 0)
4413     {
4414       sprintf(laszip_dll->error, "reader is not open");
4415       return 1;
4416     }
4417 
4418     if (laszip_dll->writer)
4419     {
4420       sprintf(laszip_dll->error, "writer is already open");
4421       return 1;
4422     }
4423 
4424     if (laszip_dll->lax_exploit == 0)
4425     {
4426       sprintf(laszip_dll->error, "exploiting of spatial indexing not enabled before opening reader");
4427       return 1;
4428     }
4429 
4430     // check if reader found spatial indexing information when opening file
4431 
4432     if (laszip_dll->lax_index)
4433     {
4434       *is_indexed = 1;
4435     }
4436     else
4437     {
4438       *is_indexed = 0;
4439     }
4440 
4441     // optional: inform whether spatial index is appended to LAZ file or in separate LAX file
4442 
4443     if (is_appended)
4444     {
4445       *is_appended = 0;
4446     }
4447 
4448   }
4449   catch (...)
4450   {
4451     sprintf(laszip_dll->error, "internal error in laszip_have_spatial_index");
4452     return 1;
4453   }
4454 
4455   laszip_dll->error[0] = '\0';
4456   return 0;
4457 }
4458 
4459 /*---------------------------------------------------------------------------*/
4460 LASZIP_API laszip_I32
laszip_inside_rectangle(laszip_POINTER pointer,const laszip_F64 r_min_x,const laszip_F64 r_min_y,const laszip_F64 r_max_x,const laszip_F64 r_max_y,laszip_BOOL * is_empty)4461 laszip_inside_rectangle(
4462     laszip_POINTER                     pointer
4463     , const laszip_F64                 r_min_x
4464     , const laszip_F64                 r_min_y
4465     , const laszip_F64                 r_max_x
4466     , const laszip_F64                 r_max_y
4467     , laszip_BOOL*                     is_empty
4468 )
4469 {
4470   if (pointer == 0) return 1;
4471   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
4472 
4473   try
4474   {
4475     if (laszip_dll->reader == 0)
4476     {
4477       sprintf(laszip_dll->error, "reader is not open");
4478       return 1;
4479     }
4480 
4481     if (is_empty == 0)
4482     {
4483       sprintf(laszip_dll->error, "laszip_BOOL pointer 'is_empty' is zero");
4484       return 1;
4485     }
4486 
4487     if (laszip_dll->lax_exploit == FALSE)
4488     {
4489       sprintf(laszip_dll->error, "exploiting of spatial indexing not enabled before opening reader");
4490       return 1;
4491     }
4492 
4493     laszip_dll->lax_r_min_x = r_min_x;
4494     laszip_dll->lax_r_min_y = r_min_y;
4495     laszip_dll->lax_r_max_x = r_max_x;
4496     laszip_dll->lax_r_max_y = r_max_y;
4497 
4498     if (laszip_dll->lax_index)
4499     {
4500       if (laszip_dll->lax_index->intersect_rectangle(r_min_x, r_min_y, r_max_x, r_max_y))
4501       {
4502         *is_empty = 0;
4503       }
4504       else
4505       {
4506         // no overlap between spatial indexing cells and query reactangle
4507         *is_empty = 1;
4508       }
4509     }
4510     else
4511     {
4512       if ((laszip_dll->header.min_x > r_max_x) || (laszip_dll->header.min_y > r_max_y) || (laszip_dll->header.max_x < r_min_x) || (laszip_dll->header.max_y < r_min_y))
4513       {
4514         // no overlap between header bouding box and query reactangle
4515         *is_empty = 1;
4516       }
4517       else
4518       {
4519         *is_empty = 0;
4520       }
4521     }
4522   }
4523   catch (...)
4524   {
4525     sprintf(laszip_dll->error, "internal error in laszip_inside_rectangle");
4526     return 1;
4527   }
4528 
4529   laszip_dll->error[0] = '\0';
4530   return 0;
4531 }
4532 
4533 /*---------------------------------------------------------------------------*/
4534 LASZIP_API laszip_I32
laszip_seek_point(laszip_POINTER pointer,laszip_I64 index)4535 laszip_seek_point(
4536     laszip_POINTER                     pointer
4537     , laszip_I64                       index
4538 )
4539 {
4540   if (pointer == 0) return 1;
4541   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
4542 
4543   try
4544   {
4545     // seek to the point
4546     if (!laszip_dll->reader->seek((U32)laszip_dll->p_count, (U32)index))
4547     {
4548 #ifdef _WIN32
4549       sprintf(laszip_dll->error, "seeking from index %I64d to index %I64d for file with %I64d points", laszip_dll->p_count, index, laszip_dll->npoints);
4550 #else
4551       sprintf(laszip_dll->error, "seeking from index %lld to index %lld for file with %lld points", laszip_dll->p_count, index, laszip_dll->npoints);
4552 #endif
4553       return 1;
4554     }
4555     laszip_dll->p_count = index;
4556   }
4557   catch (...)
4558   {
4559     sprintf(laszip_dll->error, "internal error in laszip_seek_point");
4560     return 1;
4561   }
4562 
4563   laszip_dll->error[0] = '\0';
4564   return 0;
4565 }
4566 
4567 /*---------------------------------------------------------------------------*/
4568 LASZIP_API laszip_I32
laszip_read_point(laszip_POINTER pointer)4569 laszip_read_point(
4570     laszip_POINTER                     pointer
4571 )
4572 {
4573   if (pointer == 0) return 1;
4574   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
4575 
4576   try
4577   {
4578     // read the point
4579     if (!laszip_dll->reader->read(laszip_dll->point_items))
4580     {
4581 #ifdef _WIN32
4582       sprintf(laszip_dll->error, "reading point %I64d of %I64d total points", laszip_dll->p_count, laszip_dll->npoints);
4583 #else
4584       sprintf(laszip_dll->error, "reading point %lld of %lld total points", laszip_dll->p_count, laszip_dll->npoints);
4585 #endif
4586       return 1;
4587     }
4588 
4589     // special recoding of points (in compatibility mode only)
4590 
4591     if (laszip_dll->compatibility_mode)
4592     {
4593       I16 scan_angle_remainder;
4594       U8 extended_returns;
4595       U8 classification;
4596       U8 flags_and_channel;
4597       I32 return_number_increment;
4598       I32 number_of_returns_increment;
4599       I32 overlap_bit;
4600       I32 scanner_channel;
4601 
4602       // instill extended attributes
4603       struct laszip_point* point = &laszip_dll->point;
4604 
4605       // get extended attributes from extra bytes
4606       scan_angle_remainder = *((I16*)(point->extra_bytes + laszip_dll->start_scan_angle));
4607       extended_returns = point->extra_bytes[laszip_dll->start_extended_returns];
4608       classification = point->extra_bytes[laszip_dll->start_classification];
4609       flags_and_channel = point->extra_bytes[laszip_dll->start_flags_and_channel];
4610       if (laszip_dll->start_NIR_band != -1)
4611       {
4612         point->rgb[3] = *((U16*)(point->extra_bytes + laszip_dll->start_NIR_band));
4613       }
4614 
4615       // decompose into individual attributes
4616       return_number_increment = (extended_returns >> 4) & 0x0F;
4617       number_of_returns_increment = extended_returns & 0x0F;
4618       scanner_channel = (flags_and_channel >> 1) & 0x03;
4619       overlap_bit = flags_and_channel & 0x01;
4620 
4621       // instill into point
4622       point->extended_scan_angle = scan_angle_remainder + I16_QUANTIZE(((F32)point->scan_angle_rank) / 0.006f);
4623       point->extended_return_number = return_number_increment + point->return_number;
4624       point->extended_number_of_returns = number_of_returns_increment + point->number_of_returns;
4625       point->extended_classification = classification + point->classification;
4626       point->extended_scanner_channel = scanner_channel;
4627       point->extended_classification_flags = (overlap_bit << 3) | ((point->withheld_flag) << 2) | ((point->keypoint_flag) << 1) | (point->synthetic_flag);
4628     }
4629 
4630     laszip_dll->p_count++;
4631   }
4632   catch (...)
4633   {
4634     sprintf(laszip_dll->error, "internal error in laszip_read_point");
4635     return 1;
4636   }
4637 
4638   laszip_dll->error[0] = '\0';
4639   return 0;
4640 }
4641 
4642 /*---------------------------------------------------------------------------*/
4643 LASZIP_API laszip_I32
laszip_read_inside_point(laszip_POINTER pointer,laszip_BOOL * is_done)4644 laszip_read_inside_point(
4645     laszip_POINTER                     pointer
4646     , laszip_BOOL*                     is_done
4647 )
4648 {
4649   if (pointer == 0) return 1;
4650   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
4651 
4652   try
4653   {
4654     laszip_F64 xy;
4655 
4656     *is_done = 1;
4657 
4658     if (laszip_dll->lax_index)
4659     {
4660       while (laszip_dll->lax_index->seek_next(laszip_dll->reader, laszip_dll->p_count))
4661       {
4662         if (laszip_dll->reader->read(laszip_dll->point_items))
4663         {
4664           laszip_dll->p_count++;
4665           xy = laszip_dll->header.x_scale_factor*laszip_dll->point.X+laszip_dll->header.x_offset;
4666           if (xy < laszip_dll->lax_r_min_x || xy >= laszip_dll->lax_r_max_x) continue;
4667           xy = laszip_dll->header.y_scale_factor*laszip_dll->point.Y+laszip_dll->header.y_offset;
4668           if (xy < laszip_dll->lax_r_min_y || xy >= laszip_dll->lax_r_max_y) continue;
4669           *is_done = 0;
4670           break;
4671         }
4672       }
4673     }
4674     else
4675     {
4676       while (laszip_dll->reader->read(laszip_dll->point_items))
4677       {
4678         laszip_dll->p_count++;
4679         xy = laszip_dll->header.x_scale_factor*laszip_dll->point.X+laszip_dll->header.x_offset;
4680         if (xy < laszip_dll->lax_r_min_x || xy >= laszip_dll->lax_r_max_x) continue;
4681         xy = laszip_dll->header.y_scale_factor*laszip_dll->point.Y+laszip_dll->header.y_offset;
4682         if (xy < laszip_dll->lax_r_min_y || xy >= laszip_dll->lax_r_max_y) continue;
4683         *is_done = 0;
4684         break;
4685       }
4686 
4687       if (*is_done)
4688       {
4689         if (laszip_dll->p_count < laszip_dll->npoints)
4690         {
4691 #ifdef _WIN32
4692           sprintf(laszip_dll->error, "reading point %I64d of %I64d total points", laszip_dll->p_count, laszip_dll->npoints);
4693 #else
4694           sprintf(laszip_dll->error, "reading point %lld of %lld total points", laszip_dll->p_count, laszip_dll->npoints);
4695 #endif
4696           return 1;
4697         }
4698       }
4699     }
4700   }
4701   catch (...)
4702   {
4703     sprintf(laszip_dll->error, "internal error in laszip_read_inside_point");
4704     return 1;
4705   }
4706 
4707   laszip_dll->error[0] = '\0';
4708   return 0;
4709 }
4710 
4711 /*---------------------------------------------------------------------------*/
4712 LASZIP_API laszip_I32
laszip_close_reader(laszip_POINTER pointer)4713 laszip_close_reader(
4714     laszip_POINTER                     pointer
4715 )
4716 {
4717   if (pointer == 0) return 1;
4718   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
4719   try
4720   {
4721     if (laszip_dll->reader == 0)
4722     {
4723       sprintf(laszip_dll->error, "closing reader before it was opened");
4724       return 1;
4725     }
4726 
4727     if (!laszip_dll->reader->done())
4728     {
4729       sprintf(laszip_dll->error, "done of LASreadPoint failed");
4730       return 1;
4731     }
4732 
4733     delete laszip_dll->reader;
4734     laszip_dll->reader = 0;
4735 
4736     delete [] laszip_dll->point_items;
4737     laszip_dll->point_items = 0;
4738 
4739     delete laszip_dll->streamin;
4740     laszip_dll->streamin = 0;
4741 
4742     if (laszip_dll->lax_index)
4743     {
4744       delete laszip_dll->lax_index;
4745       laszip_dll->lax_index = 0;
4746     }
4747 
4748   	if (laszip_dll->file)
4749     {
4750       fclose(laszip_dll->file);
4751       laszip_dll->file = 0;
4752     }
4753   }
4754   catch (...)
4755   {
4756     sprintf(laszip_dll->error, "internal error in laszip_close_reader");
4757     return 1;
4758   }
4759 
4760   laszip_dll->error[0] = '\0';
4761   return 0;
4762 }
4763 
4764 #ifdef __cplusplus
4765 
4766 /*---------------------------------------------------------------------------*/
4767 LASZIP_API laszip_I32
laszip_open_reader_stream(laszip_POINTER pointer,istream & stream,laszip_BOOL * is_compressed)4768 laszip_open_reader_stream(
4769     laszip_POINTER                     pointer
4770     , istream&                         stream
4771     , laszip_BOOL*                     is_compressed
4772 )
4773 {
4774   if (pointer == 0) return 1;
4775   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
4776 
4777   try
4778   {
4779     if (is_compressed == 0)
4780     {
4781       sprintf(laszip_dll->error, "laszip_BOOL pointer 'is_compressed' is zero");
4782       return 1;
4783     }
4784 
4785     if (laszip_dll->writer)
4786     {
4787       sprintf(laszip_dll->error, "writer is already open");
4788       return 1;
4789     }
4790 
4791     if (laszip_dll->reader)
4792     {
4793       sprintf(laszip_dll->error, "reader is already open");
4794       return 1;
4795     }
4796 
4797     // open the file
4798 
4799     if (IS_LITTLE_ENDIAN())
4800       laszip_dll->streamin = new ByteStreamInIstreamLE(stream);
4801     else
4802       laszip_dll->streamin = new ByteStreamInIstreamBE(stream);
4803 
4804     if (laszip_dll->streamin == 0)
4805     {
4806       sprintf(laszip_dll->error, "could not alloc ByteStreamInIstream");
4807       return 1;
4808     }
4809 
4810     return laszip_read_header(laszip_dll, is_compressed);
4811   }
4812   catch (...)
4813   {
4814     sprintf(laszip_dll->error, "internal error in laszip_open_reader");
4815     return 1;
4816   }
4817 }
4818 
4819 /*---------------------------------------------------------------------------*/
4820 // The stream writer also supports software that writes the LAS header on its
4821 // own simply by setting the BOOL 'do_not_write_header' to TRUE. This function
4822 // should then be called just prior to writing points as data is then written
4823 // to the current stream position
4824 LASZIP_API laszip_I32
laszip_open_writer_stream(laszip_POINTER pointer,ostream & stream,laszip_BOOL compress,laszip_BOOL do_not_write_header)4825 laszip_open_writer_stream(
4826     laszip_POINTER                     pointer
4827     , ostream&                         stream
4828     , laszip_BOOL                      compress
4829     , laszip_BOOL                      do_not_write_header
4830 )
4831 {
4832   if (pointer == 0) return 1;
4833   laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
4834 
4835   try
4836   {
4837     if (laszip_dll->writer)
4838     {
4839       sprintf(laszip_dll->error, "writer is already open");
4840       return 1;
4841     }
4842 
4843     if (laszip_dll->reader)
4844     {
4845       sprintf(laszip_dll->error, "reader is already open");
4846       return 1;
4847     }
4848 
4849     // create the outstream
4850 
4851     if (IS_LITTLE_ENDIAN())
4852       laszip_dll->streamout = new ByteStreamOutOstreamLE(stream);
4853     else
4854       laszip_dll->streamout = new ByteStreamOutOstreamBE(stream);
4855 
4856     if (laszip_dll->streamout == 0)
4857     {
4858       sprintf(laszip_dll->error, "could not alloc ByteStreamOutOstream");
4859       return 1;
4860     }
4861 
4862     // setup the items that make up the point
4863 
4864     LASzip laszip;
4865     if (setup_laszip_items(laszip_dll, &laszip, compress))
4866     {
4867       return 1;
4868     }
4869 
4870     // this supports software that writes the LAS header on its own
4871 
4872     if (do_not_write_header == FALSE)
4873     {
4874       // prepare header
4875 
4876       if (laszip_prepare_header_for_write(laszip_dll))
4877       {
4878         return 1;
4879       }
4880 
4881       // prepare point
4882 
4883       if (laszip_prepare_point_for_write(laszip_dll, compress))
4884       {
4885         return 1;
4886       }
4887 
4888       // prepare VLRs
4889 
4890       if (laszip_prepare_vlrs_for_write(laszip_dll))
4891       {
4892         return 1;
4893       }
4894 
4895       // write header variable after variable
4896 
4897       if (laszip_write_header(laszip_dll, &laszip, compress))
4898       {
4899         return 1;
4900       }
4901     }
4902 
4903     // create the point writer
4904 
4905     if (create_point_writer(laszip_dll, &laszip))
4906     {
4907       return 1;
4908     }
4909 
4910     // set the point number and point count
4911 
4912     laszip_dll->npoints = (laszip_dll->header.number_of_point_records ? laszip_dll->header.number_of_point_records : laszip_dll->header.extended_number_of_point_records);
4913     laszip_dll->p_count = 0;
4914   }
4915   catch (...)
4916   {
4917     sprintf(laszip_dll->error, "internal error in laszip_open_writer_stream.");
4918     return 1;
4919   }
4920   laszip_dll->error[0] = '\0';
4921   return 0;
4922 }
4923 
4924 /*---------------------------------------------------------------------------*/
4925 // creates complete LASzip VLR for currently selected point type and compression
4926 // The VLR data is valid until the laszip_dll pointer is destroyed.
4927 LASZIP_API laszip_I32
laszip_create_laszip_vlr(laszip_POINTER pointer,laszip_U8 ** vlr,laszip_U32 * vlr_size)4928 laszip_create_laszip_vlr(
4929     laszip_POINTER                     pointer
4930     , laszip_U8**                      vlr
4931     , laszip_U32*                      vlr_size
4932 )
4933 {
4934   if (pointer == 0) return 1;
4935   laszip_dll_struct *laszip_dll = (laszip_dll_struct *)pointer;
4936 
4937   LASzip laszip;
4938   if (setup_laszip_items(laszip_dll, &laszip, TRUE))
4939   {
4940     return 1;
4941   }
4942 
4943   ByteStreamOutArray* out = 0;
4944 
4945   if (IS_LITTLE_ENDIAN())
4946     out = new ByteStreamOutArrayLE();
4947   else
4948     out = new ByteStreamOutArrayBE();
4949 
4950   if (out == 0)
4951   {
4952     sprintf(laszip_dll->error, "could not alloc ByteStreamOutArray");
4953     return 1;
4954   }
4955 
4956   if (write_laszip_vlr_header(laszip_dll, &laszip, out))
4957   {
4958     return 1;
4959   }
4960 
4961   if (write_laszip_vlr_payload(laszip_dll, &laszip, out))
4962   {
4963     return 1;
4964   }
4965 
4966   *vlr = (laszip_U8*)malloc(out->getSize());
4967   *vlr_size = (U32)out->getSize();
4968   laszip_dll->buffers.push_back(*vlr);
4969   memcpy(*vlr, out->getData(), out->getSize());
4970 
4971   delete out;
4972 
4973   laszip_dll->error[0] = '\0';
4974   return 0;
4975 }
4976 
4977 #endif // __cplusplus
4978