1 /*
2 ===============================================================================
3 
4   FILE:  laszip.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     see corresponding header file
28 
29 ===============================================================================
30 */
31 #include "laszip.hpp"
32 
33 #include "mydefs.hpp"
34 
35 #include <assert.h>
36 
37 #include <string.h>
38 #include <stdlib.h>
39 #include <stdio.h>
40 
LASzip()41 LASzip::LASzip()
42 {
43   compressor = LASZIP_COMPRESSOR_DEFAULT;
44   coder = LASZIP_CODER_ARITHMETIC;
45   version_major = LASZIP_VERSION_MAJOR;
46   version_minor = LASZIP_VERSION_MINOR;
47   version_revision = LASZIP_VERSION_REVISION;
48   options = 0;
49   num_items = 0;
50   chunk_size = LASZIP_CHUNK_SIZE_DEFAULT;
51   number_of_special_evlrs = -1;
52   offset_to_special_evlrs = -1;
53   error_string = 0;
54   items = 0;
55   bytes = 0;
56 }
57 
~LASzip()58 LASzip::~LASzip()
59 {
60   if (error_string) free(error_string);
61   if (items) delete [] items;
62   if (bytes) delete [] bytes;
63 }
64 
65 // the data of the LASzip VLR
66 //     U16  compressor         2 bytes
67 //     U16  coder              2 bytes
68 //     U8   version_major      1 byte
69 //     U8   version_minor      1 byte
70 //     U16  version_revision   2 bytes
71 //     U32  options            4 bytes
72 //     U32  chunk_size         4 bytes
73 //     I64  num_points         8 bytes
74 //     I64  num_bytes          8 bytes
75 //     U16  num_items          2 bytes
76 //        U16 type                2 bytes * num_items
77 //        U16 size                2 bytes * num_items
78 //        U16 version             2 bytes * num_items
79 // which totals 34+6*num_items
80 
81 // unpack from VLR data
unpack(const U8 * bytes,const I32 num)82 bool LASzip::unpack(const U8* bytes, const I32 num)
83 {
84   // check input
85   if (num < 34) return return_error("too few bytes to unpack");
86   if (((num - 34) % 6) != 0) return return_error("wrong number bytes to unpack");
87   if (((num - 34) / 6) == 0) return return_error("zero items to unpack");
88   num_items = (num - 34) / 6;
89 
90   // create item list
91   if (items) delete [] items;
92   items = new LASitem[num_items];
93 
94   // do the unpacking
95   U16 i;
96   const U8* b = bytes;
97   compressor = *((U16*)b);
98   b += 2;
99   coder = *((U16*)b);
100   b += 2;
101   version_major = *((U8*)b);
102   b += 1;
103   version_minor = *((U8*)b);
104   b += 1;
105   version_revision = *((U16*)b);
106   b += 2;
107   options = *((U32*)b);
108   b += 4;
109   chunk_size = *((U32*)b);
110   b += 4;
111   number_of_special_evlrs = *((I64*)b);
112   b += 8;
113   offset_to_special_evlrs = *((I64*)b);
114   b += 8;
115   num_items = *((U16*)b);
116   b += 2;
117   for (i = 0; i < num_items; i++)
118   {
119     items[i].type = (LASitem::Type)*((U16*)b);
120     b += 2;
121     items[i].size = *((U16*)b);
122     b += 2;
123     items[i].version = *((U16*)b);
124     b += 2;
125   }
126   assert((bytes + num) == b);
127 
128   // check if we support the contents
129 
130   for (i = 0; i < num_items; i++)
131   {
132     if (!check_item(&items[i])) return false;
133   }
134   return true;
135 }
136 
137 // pack to VLR data
pack(U8 * & bytes,I32 & num)138 bool LASzip::pack(U8*& bytes, I32& num)
139 {
140   // check if we support the contents
141   if (!check()) return false;
142 
143   // prepare output
144   num = 34 + 6*num_items;
145   if (this->bytes) delete [] this->bytes;
146   this->bytes = bytes = new U8[num];
147 
148   // pack
149   U16 i;
150   U8* b = bytes;
151   *((U16*)b) = compressor;
152   b += 2;
153   *((U16*)b) = coder;
154   b += 2;
155   *((U8*)b) = version_major;
156   b += 1;
157   *((U8*)b) = version_minor;
158   b += 1;
159   *((U16*)b) = version_revision;
160   b += 2;
161   *((U32*)b) = options;
162   b += 4;
163   *((U32*)b) = chunk_size;
164   b += 4;
165   *((I64*)b) = number_of_special_evlrs;
166   b += 8;
167   *((I64*)b) = offset_to_special_evlrs;
168   b += 8;
169   *((U16*)b) = num_items;
170   b += 2;
171   for (i = 0; i < num_items; i++)
172   {
173     *((U16*)b) = (U16)items[i].type;
174     b += 2;
175     *((U16*)b) = items[i].size;
176     b += 2;
177     *((U16*)b) = items[i].version;
178     b += 2;
179   }
180   assert((bytes + num) == b);
181   return true;
182 }
183 
get_error() const184 const char* LASzip::get_error() const
185 {
186   return error_string;
187 }
188 
return_error(const char * error)189 bool LASzip::return_error(const char* error)
190 {
191 
192 #if defined(_MSC_VER) && \
193     (_MSC_FULL_VER >= 150000000)
194 #define CopyString _strdup
195 #else
196 #define CopyString strdup
197 #endif
198   char err[256];
199   sprintf(err, "%s (LASzip v%d.%dr%d)", error, LASZIP_VERSION_MAJOR, LASZIP_VERSION_MINOR, LASZIP_VERSION_REVISION);
200   if (error_string) free(error_string);
201   error_string = CopyString(err);
202   return false;
203 }
204 
check_compressor(const U16 compressor)205 bool LASzip::check_compressor(const U16 compressor)
206 {
207   if (compressor < LASZIP_COMPRESSOR_TOTAL_NUMBER_OF) return true;
208   char error[64];
209   sprintf(error, "compressor %d not supported", compressor);
210   return return_error(error);
211 }
212 
check_coder(const U16 coder)213 bool LASzip::check_coder(const U16 coder)
214 {
215   if (coder < LASZIP_CODER_TOTAL_NUMBER_OF) return true;
216   char error[64];
217   sprintf(error, "coder %d not supported", coder);
218   return return_error(error);
219 }
220 
check_item(const LASitem * item)221 bool LASzip::check_item(const LASitem* item)
222 {
223   switch (item->type)
224   {
225   case LASitem::POINT10:
226     if (item->size != 20) return return_error("POINT10 has size != 20");
227     if (item->version > 2) return return_error("POINT10 has version > 2");
228     break;
229   case LASitem::GPSTIME11:
230     if (item->size != 8) return return_error("GPSTIME11 has size != 8");
231     if (item->version > 2) return return_error("GPSTIME11 has version > 2");
232     break;
233   case LASitem::RGB12:
234     if (item->size != 6) return return_error("RGB12 has size != 6");
235     if (item->version > 2) return return_error("RGB12 has version > 2");
236     break;
237   case LASitem::BYTE:
238     if (item->size < 1) return return_error("BYTE has size < 1");
239     if (item->version > 2) return return_error("BYTE has version > 2");
240     break;
241   case LASitem::POINT14:
242     if (item->size != 30) return return_error("POINT14 has size != 30");
243     if ((item->version != 0) && (item->version != 2) && (item->version != 3) && (item->version != 4)) return return_error("POINT14 has version != 0 and != 2 and != 3 and != 4"); // version == 2 from lasproto, version == 4 fixes context-switch
244     break;
245   case LASitem::RGB14:
246     if (item->size != 6) return return_error("RGB14 has size != 6");
247     if ((item->version != 0) && (item->version != 2) && (item->version != 3) && (item->version != 4)) return return_error("RGB14 has version != 0 and != 2 and != 3 and != 4"); // version == 2 from lasproto, version == 4 fixes context-switch
248     break;
249   case LASitem::RGBNIR14:
250     if (item->size != 8) return return_error("RGBNIR14 has size != 8");
251     if ((item->version != 0) && (item->version != 2) && (item->version != 3) && (item->version != 4)) return return_error("RGBNIR14 has version != 0 and != 2 and != 3 and != 4"); // version == 2 from lasproto, version == 4 fixes context-switch
252     break;
253   case LASitem::BYTE14:
254     if (item->size < 1) return return_error("BYTE14 has size < 1");
255     if ((item->version != 0) && (item->version != 2) && (item->version != 3) && (item->version != 4)) return return_error("BYTE14 has version != 0 and != 2 and != 3 and != 4"); // version == 2 from lasproto, version == 4 fixes context-switch
256     break;
257   case LASitem::WAVEPACKET13:
258     if (item->size != 29) return return_error("WAVEPACKET13 has size != 29");
259     if (item->version > 1) return return_error("WAVEPACKET13 has version > 1");
260     break;
261   case LASitem::WAVEPACKET14:
262     if (item->size != 29) return return_error("WAVEPACKET14 has size != 29");
263     if ((item->version != 0) && (item->version != 3) && (item->version != 4)) return return_error("WAVEPACKET14 has version != 0 and != 3 and != 4"); // version == 4 fixes context-switch
264     break;
265   default:
266     if (1)
267     {
268       char error[64];
269       sprintf(error, "item unknown (%d,%d,%d)", item->type, item->size, item->version);
270       return return_error(error);
271     }
272   }
273   return true;
274 }
275 
check_items(const U16 num_items,const LASitem * items,const U16 point_size)276 bool LASzip::check_items(const U16 num_items, const LASitem* items, const U16 point_size)
277 {
278   if (num_items == 0) return return_error("number of items cannot be zero");
279   if (items == 0) return return_error("items pointer cannot be NULL");
280   U16 i;
281   U16 size = 0;
282   for (i = 0; i < num_items; i++)
283   {
284     if (!check_item(&items[i])) return false;
285     size += items[i].size;
286   }
287   if (point_size && (point_size != size))
288   {
289     CHAR temp[66];
290     sprintf(temp, "point has size of %d but items only add up to %d bytes", point_size, size);
291     return return_error(temp);
292   }
293   return true;
294 }
295 
check(const U16 point_size)296 bool LASzip::check(const U16 point_size)
297 {
298   if (!check_compressor(compressor)) return false;
299   if (!check_coder(coder)) return false;
300   if (!check_items(num_items, items, point_size)) return false;
301   return true;
302 }
303 
request_compatibility_mode(const U16 requested_compatibility_mode)304 bool LASzip::request_compatibility_mode(const U16 requested_compatibility_mode)
305 {
306   if (num_items != 0) return return_error("request compatibility mode before calling setup()");
307   if (requested_compatibility_mode > 1)
308   {
309     return return_error("compatibility mode larger than 1 not supported");
310   }
311   if (requested_compatibility_mode)
312   {
313     options = options | 0x00000001;
314   }
315   else
316   {
317     options = options & 0xFFFFFFFE;
318   }
319   return true;
320 }
321 
setup(const U8 point_type,const U16 point_size,const U16 compressor)322 bool LASzip::setup(const U8 point_type, const U16 point_size, const U16 compressor)
323 {
324   if (!check_compressor(compressor)) return false;
325   this->num_items = 0;
326   if (this->items) delete [] this->items;
327   this->items = 0;
328   if (!setup(&num_items, &items, point_type, point_size, compressor)) return false;
329   if (compressor)
330   {
331     if (items[0].type == LASitem::POINT14)
332     {
333       if (compressor != LASZIP_COMPRESSOR_LAYERED_CHUNKED)
334       {
335         return false;
336       }
337       this->compressor = LASZIP_COMPRESSOR_LAYERED_CHUNKED;
338     }
339     else
340     {
341       if (compressor == LASZIP_COMPRESSOR_LAYERED_CHUNKED)
342       {
343         this->compressor = LASZIP_COMPRESSOR_CHUNKED;
344       }
345       else
346       {
347         this->compressor = compressor;
348       }
349     }
350     if (compressor != LASZIP_COMPRESSOR_POINTWISE)
351     {
352       if (chunk_size == 0) chunk_size = LASZIP_CHUNK_SIZE_DEFAULT;
353     }
354   }
355   else
356   {
357     this->compressor = LASZIP_COMPRESSOR_NONE;
358   }
359   return true;
360 }
361 
setup(const U16 num_items,const LASitem * items,const U16 compressor)362 bool LASzip::setup(const U16 num_items, const LASitem* items, const U16 compressor)
363 {
364   // check input
365   if (!check_compressor(compressor)) return false;
366   if (!check_items(num_items, items)) return false;
367 
368   // setup compressor
369   if (compressor)
370   {
371     if (items[0].type == LASitem::POINT14)
372     {
373       if (compressor != LASZIP_COMPRESSOR_LAYERED_CHUNKED)
374       {
375         return false;
376       }
377       this->compressor = LASZIP_COMPRESSOR_LAYERED_CHUNKED;
378     }
379     else
380     {
381       if (compressor == LASZIP_COMPRESSOR_LAYERED_CHUNKED)
382       {
383         this->compressor = LASZIP_COMPRESSOR_CHUNKED;
384       }
385       else
386       {
387         this->compressor = compressor;
388       }
389     }
390     if (compressor != LASZIP_COMPRESSOR_POINTWISE)
391     {
392       if (chunk_size == 0) chunk_size = LASZIP_CHUNK_SIZE_DEFAULT;
393     }
394   }
395   else
396   {
397     this->compressor = LASZIP_COMPRESSOR_NONE;
398   }
399 
400   // prepare items
401   this->num_items = 0;
402   if (this->items) delete [] this->items;
403   this->items = 0;
404   this->num_items = num_items;
405   this->items = new LASitem[num_items];
406 
407   // setup items
408   U16 i;
409   for (i = 0; i < num_items; i++)
410   {
411     this->items[i] = items[i];
412   }
413 
414   return true;
415 }
416 
setup(U16 * num_items,LASitem ** items,const U8 point_type,const U16 point_size,const U16 compressor)417 bool LASzip::setup(U16* num_items, LASitem** items, const U8 point_type, const U16 point_size, const U16 compressor)
418 {
419   BOOL compatible = FALSE;
420   BOOL have_point14 = FALSE;
421   BOOL have_gps_time = FALSE;
422   BOOL have_rgb = FALSE;
423   BOOL have_nir = FALSE;
424   BOOL have_wavepacket = FALSE;
425   I32 extra_bytes_number = 0;
426 
427   // turns on LAS 1.4 compatibility mode
428 
429   if (options & 1) compatible = TRUE;
430 
431   // switch over the point types we know
432   switch (point_type)
433   {
434   case 0:
435     extra_bytes_number = (I32)point_size - 20;
436     break;
437   case 1:
438     have_gps_time = TRUE;
439     extra_bytes_number = (I32)point_size - 28;
440     break;
441   case 2:
442     have_rgb = TRUE;
443     extra_bytes_number = (I32)point_size - 26;
444     break;
445   case 3:
446     have_gps_time = TRUE;
447     have_rgb = TRUE;
448     extra_bytes_number = (I32)point_size - 34;
449     break;
450   case 4:
451     have_gps_time = TRUE;
452     have_wavepacket = TRUE;
453     extra_bytes_number = (I32)point_size - 57;
454     break;
455   case 5:
456     have_gps_time = TRUE;
457     have_rgb = TRUE;
458     have_wavepacket = TRUE;
459     extra_bytes_number = (I32)point_size - 63;
460     break;
461   case 6:
462     have_point14 = TRUE;
463     extra_bytes_number = (I32)point_size - 30;
464     break;
465   case 7:
466     have_point14 = TRUE;
467     have_rgb = TRUE;
468     extra_bytes_number = (I32)point_size - 36;
469     break;
470   case 8:
471     have_point14 = TRUE;
472     have_rgb = TRUE;
473     have_nir = TRUE;
474     extra_bytes_number = (I32)point_size - 38;
475     break;
476   case 9:
477     have_point14 = TRUE;
478     have_wavepacket = TRUE;
479     extra_bytes_number = (I32)point_size - 59;
480     break;
481   case 10:
482     have_point14 = TRUE;
483     have_rgb = TRUE;
484     have_nir = TRUE;
485     have_wavepacket = TRUE;
486     extra_bytes_number = (I32)point_size - 67;
487     break;
488   default:
489     if (1)
490     {
491       char error[64];
492       sprintf(error, "point type %d unknown", point_type);
493       return return_error(error);
494     }
495   }
496 
497   if (extra_bytes_number < 0)
498   {
499     fprintf(stderr, "WARNING: point size %d too small by %d bytes for point type %d. assuming point_size of %d\n", point_size, -extra_bytes_number, point_type, point_size-extra_bytes_number);
500     extra_bytes_number = 0;
501   }
502 
503   // maybe represent new LAS 1.4 as corresponding LAS 1.3 points plus extra bytes for compatibility
504   if (have_point14 && compatible)
505   {
506     // we need 4 extra bytes for the new point attributes
507     extra_bytes_number += 5;
508     // we store the GPS time separately
509     have_gps_time = TRUE;
510     // we do not use the point14 item
511     have_point14 = FALSE;
512     // if we have NIR ...
513     if (have_nir)
514     {
515       // we need another 2 extra bytes
516       extra_bytes_number += 2;
517       // we do not use the NIR item
518       have_nir = FALSE;
519     }
520   }
521 
522   // create item description
523 
524   (*num_items) = 1 + !!(have_gps_time) + !!(have_rgb) + !!(have_wavepacket) + !!(extra_bytes_number);
525   (*items) = new LASitem[*num_items];
526 
527   U16 i = 1;
528   if (have_point14)
529   {
530     (*items)[0].type = LASitem::POINT14;
531     (*items)[0].size = 30;
532     (*items)[0].version = 0;
533   }
534   else
535   {
536     (*items)[0].type = LASitem::POINT10;
537     (*items)[0].size = 20;
538     (*items)[0].version = 0;
539   }
540   if (have_gps_time)
541   {
542     (*items)[i].type = LASitem::GPSTIME11;
543     (*items)[i].size = 8;
544     (*items)[i].version = 0;
545     i++;
546   }
547   if (have_rgb)
548   {
549     if (have_point14)
550 	  {
551       if (have_nir)
552       {
553         (*items)[i].type = LASitem::RGBNIR14;
554         (*items)[i].size = 8;
555         (*items)[i].version = 0;
556       }
557 		  else
558       {
559         (*items)[i].type = LASitem::RGB14;
560         (*items)[i].size = 6;
561         (*items)[i].version = 0;
562       }
563     }
564     else
565     {
566       (*items)[i].type = LASitem::RGB12;
567       (*items)[i].size = 6;
568       (*items)[i].version = 0;
569     }
570     i++;
571   }
572   if (have_wavepacket)
573   {
574     if (have_point14)
575 	  {
576       (*items)[i].type = LASitem::WAVEPACKET14;
577       (*items)[i].size = 29;
578       (*items)[i].version = 0;
579     }
580     else
581 	  {
582       (*items)[i].type = LASitem::WAVEPACKET13;
583       (*items)[i].size = 29;
584       (*items)[i].version = 0;
585     }
586     i++;
587   }
588   if (extra_bytes_number)
589   {
590     if (have_point14)
591 	  {
592       (*items)[i].type = LASitem::BYTE14;
593       (*items)[i].size = extra_bytes_number;
594       (*items)[i].version = 0;
595     }
596     else
597 	  {
598       (*items)[i].type = LASitem::BYTE;
599       (*items)[i].size = extra_bytes_number;
600       (*items)[i].version = 0;
601     }
602     i++;
603   }
604   if (compressor) request_version(2);
605   assert(i == *num_items);
606   return true;
607 }
608 
set_chunk_size(const U32 chunk_size)609 bool LASzip::set_chunk_size(const U32 chunk_size)
610 {
611   if (num_items == 0) return return_error("call setup() before setting chunk size");
612   if (this->compressor != LASZIP_COMPRESSOR_POINTWISE)
613   {
614     this->chunk_size = chunk_size;
615     return true;
616   }
617   return false;
618 }
619 
request_version(const U16 requested_version)620 bool LASzip::request_version(const U16 requested_version)
621 {
622   if (num_items == 0) return return_error("call setup() before requesting version");
623   if (compressor == LASZIP_COMPRESSOR_NONE)
624   {
625     if (requested_version > 0) return return_error("without compression version is always 0");
626   }
627   else
628   {
629     if (requested_version < 1) return return_error("with compression version is at least 1");
630     if (requested_version > 2) return return_error("version larger than 2 not supported");
631   }
632   U16 i;
633   for (i = 0; i < num_items; i++)
634   {
635     switch (items[i].type)
636     {
637     case LASitem::POINT10:
638     case LASitem::GPSTIME11:
639     case LASitem::RGB12:
640     case LASitem::BYTE:
641       items[i].version = requested_version;
642       break;
643     case LASitem::WAVEPACKET13:
644       items[i].version = 1; // no version 2
645       break;
646     case LASitem::POINT14:
647     case LASitem::RGB14:
648     case LASitem::RGBNIR14:
649     case LASitem::WAVEPACKET14:
650     case LASitem::BYTE14:
651       items[i].version = 3; // no version 1 or 2
652       break;
653     default:
654       return return_error("item type not supported");
655     }
656   }
657   return true;
658 }
659 
is_standard(U8 * point_type,U16 * record_length)660 bool LASzip::is_standard(U8* point_type, U16* record_length)
661 {
662   return is_standard(num_items, items, point_type, record_length);
663 }
664 
is_standard(const U16 num_items,const LASitem * items,U8 * point_type,U16 * record_length)665 bool LASzip::is_standard(const U16 num_items, const LASitem* items, U8* point_type, U16* record_length)
666 {
667   if (items == 0) return return_error("LASitem array is zero");
668 
669   // this is always true
670   if (point_type) *point_type = 127;
671   if (record_length)
672   {
673     U16 i;
674     *record_length = 0;
675     for (i = 0; i < num_items; i++)
676     {
677       *record_length += items[i].size;
678     }
679   }
680 
681   // the minimal number of items is 1
682   if (num_items < 1) return return_error("less than one LASitem entries");
683   // the maximal number of items is 5
684   if (num_items > 5) return return_error("more than five LASitem entries");
685 
686   if (items[0].is_type(LASitem::POINT10))
687   {
688     // consider all the POINT10 combinations
689     if (num_items == 1)
690     {
691       if (point_type) *point_type = 0;
692       if (record_length) assert(*record_length == 20);
693       return true;
694     }
695     else
696     {
697       if (items[1].is_type(LASitem::GPSTIME11))
698       {
699         if (num_items == 2)
700         {
701           if (point_type) *point_type = 1;
702           if (record_length) assert(*record_length == 28);
703           return true;
704         }
705         else
706         {
707           if (items[2].is_type(LASitem::RGB12))
708           {
709             if (num_items == 3)
710             {
711               if (point_type) *point_type = 3;
712               if (record_length) assert(*record_length == 34);
713               return true;
714             }
715             else
716             {
717               if (items[3].is_type(LASitem::WAVEPACKET13))
718               {
719                 if (num_items == 4)
720                 {
721                   if (point_type) *point_type = 5;
722                   if (record_length) assert(*record_length == 63);
723                   return true;
724                 }
725                 else
726                 {
727                   if (items[4].is_type(LASitem::BYTE))
728                   {
729                     if (num_items == 5)
730                     {
731                       if (point_type) *point_type = 5;
732                       if (record_length) assert(*record_length == (63 + items[4].size));
733                       return true;
734                     }
735                   }
736                 }
737               }
738               else if (items[3].is_type(LASitem::BYTE))
739               {
740                 if (num_items == 4)
741                 {
742                   if (point_type) *point_type = 3;
743                   if (record_length) assert(*record_length == (34 + items[3].size));
744                   return true;
745                 }
746               }
747             }
748           }
749           else if (items[2].is_type(LASitem::WAVEPACKET13))
750           {
751             if (num_items == 3)
752             {
753               if (point_type) *point_type = 4;
754               if (record_length) assert(*record_length == 57);
755               return true;
756             }
757             else
758             {
759               if (items[3].is_type(LASitem::BYTE))
760               {
761                 if (num_items == 4)
762                 {
763                   if (point_type) *point_type = 4;
764                   if (record_length) assert(*record_length == (57 + items[3].size));
765                   return true;
766                 }
767               }
768             }
769           }
770           else if (items[2].is_type(LASitem::BYTE))
771           {
772             if (num_items == 3)
773             {
774               if (point_type) *point_type = 1;
775               if (record_length) assert(*record_length == (28 + items[2].size));
776               return true;
777             }
778           }
779         }
780       }
781       else if (items[1].is_type(LASitem::RGB12))
782       {
783         if (num_items == 2)
784         {
785           if (point_type) *point_type = 2;
786           if (record_length) assert(*record_length == 26);
787           return true;
788         }
789         else
790         {
791           if (items[2].is_type(LASitem::BYTE))
792           {
793             if (num_items == 3)
794             {
795               if (point_type) *point_type = 2;
796               if (record_length) assert(*record_length == (26 + items[2].size));
797               return true;
798             }
799           }
800         }
801       }
802       else if (items[1].is_type(LASitem::BYTE))
803       {
804         if (num_items == 2)
805         {
806           if (point_type) *point_type = 0;
807           if (record_length) assert(*record_length == (20 + items[1].size));
808           return true;
809         }
810       }
811     }
812   }
813   else if (items[0].is_type(LASitem::POINT14))
814   {
815     // consider all the POINT14 combinations
816     if (num_items == 1)
817     {
818       if (point_type) *point_type = 6;
819       if (record_length) assert(*record_length == 30);
820       return true;
821     }
822     else
823     {
824       if (items[1].is_type(LASitem::RGB14))
825       {
826         if (num_items == 2)
827         {
828           if (point_type) *point_type = 7;
829           if (record_length) assert(*record_length == 36);
830           return true;
831         }
832         else
833         {
834           if (items[2].is_type(LASitem::BYTE) || items[2].is_type(LASitem::BYTE14))
835           {
836             if (num_items == 3)
837             {
838               if (point_type) *point_type = 7;
839               if (record_length) assert(*record_length == (36 + items[2].size));
840               return true;
841             }
842           }
843         }
844       }
845       else if (items[1].is_type(LASitem::RGBNIR14))
846       {
847         if (num_items == 2)
848         {
849           if (point_type) *point_type = 8;
850           if (record_length) assert(*record_length == 38);
851           return true;
852         }
853         else
854         {
855           if (items[2].is_type(LASitem::WAVEPACKET13) || items[1].is_type(LASitem::WAVEPACKET14))
856           {
857             if (num_items == 3)
858             {
859               if (point_type) *point_type = 10;
860               if (record_length) assert(*record_length == 67);
861               return true;
862             }
863             else
864             {
865               if (items[3].is_type(LASitem::BYTE) || items[3].is_type(LASitem::BYTE14))
866               {
867                 if (num_items == 4)
868                 {
869                   if (point_type) *point_type = 10;
870                   if (record_length) assert(*record_length == (67 + items[3].size));
871                   return true;
872                 }
873               }
874             }
875           }
876           else if (items[2].is_type(LASitem::BYTE) || items[2].is_type(LASitem::BYTE14))
877           {
878             if (num_items == 3)
879             {
880               if (point_type) *point_type = 8;
881               if (record_length) assert(*record_length == (38 + items[2].size));
882               return true;
883             }
884           }
885         }
886       }
887       else if (items[1].is_type(LASitem::WAVEPACKET13) || items[1].is_type(LASitem::WAVEPACKET14))
888       {
889         if (num_items == 2)
890         {
891           if (point_type) *point_type = 9;
892           if (record_length) assert(*record_length == 59);
893           return true;
894         }
895         else
896         {
897           if (items[2].is_type(LASitem::BYTE) || items[2].is_type(LASitem::BYTE14))
898           {
899             if (num_items == 3)
900             {
901               if (point_type) *point_type = 9;
902               if (record_length) assert(*record_length == (59 + items[2].size));
903               return true;
904             }
905           }
906         }
907       }
908       else if (items[1].is_type(LASitem::BYTE) || items[1].is_type(LASitem::BYTE14))
909       {
910         if (num_items == 2)
911         {
912           if (point_type) *point_type = 6;
913           if (record_length) assert(*record_length == (30 + items[1].size));
914           return true;
915         }
916       }
917     }
918   }
919   else
920   {
921     return_error("first LASitem is neither POINT10 nor POINT14");
922   }
923   return return_error("LASitem array does not match LAS specification 1.4");
924 }
925 
is_type(LASitem::Type t) const926 bool LASitem::is_type(LASitem::Type t) const
927 {
928   if (t != type) return false;
929   switch (t)
930   {
931   case POINT10:
932       if (size != 20) return false;
933       break;
934   case POINT14:
935       if (size != 30) return false;
936       break;
937   case GPSTIME11:
938       if (size != 8) return false;
939       break;
940   case RGB12:
941       if (size != 6) return false;
942       break;
943   case BYTE:
944       if (size < 1) return false;
945       break;
946   case RGB14:
947       if (size != 6) return false;
948       break;
949   case RGBNIR14:
950       if (size != 8) return false;
951       break;
952   case BYTE14:
953       if (size < 1) return false;
954       break;
955   case WAVEPACKET13:
956       if (size != 29) return false;
957       break;
958   case WAVEPACKET14:
959       if (size != 29) return false;
960       break;
961   default:
962       return false;
963   }
964   return true;
965 }
966 
get_name() const967 const char* LASitem::get_name() const
968 {
969   switch (type)
970   {
971   case POINT10:
972       return "POINT10";
973       break;
974   case POINT14:
975       return "POINT14";
976       break;
977   case GPSTIME11:
978       return "GPSTIME11";
979       break;
980   case RGB12:
981       return "RGB12";
982       break;
983   case BYTE:
984       return "BYTE";
985       break;
986   case RGB14:
987       return "RGB14";
988       break;
989   case RGBNIR14:
990       return "RGBNIR14";
991       break;
992   case BYTE14:
993       return "BYTE14";
994       break;
995   case WAVEPACKET13:
996       return "WAVEPACKET13";
997       break;
998   case WAVEPACKET14:
999       return "WAVEPACKET14";
1000       break;
1001   default:
1002       break;
1003   }
1004   return 0;
1005 }
1006 
1007