Example #1
0
		public int laszip_open_writer(string file_name, bool compress)
		{
			if(file_name==null||file_name.Length==0)
			{
				error="string file_name pointer is zero";
				return 1;
			}

			if(reader!=null)
			{
				error="reader is already open";
				return 1;
			}

			if(writer!=null)
			{
				error="writer is already open";
				return 1;
			}

			try
			{
				#region check header and prepare point

				uint vlrs_size=0;

				if(header.version_major!=1)
				{
					error=string.Format("unknown LAS version {0}.{1}", header.version_major, header.version_minor);
					return 1;
				}

				if(compress&&(header.point_data_format>5))
				{
					error=string.Format("compressor does not yet support point data format {1}", header.point_data_format);
					return 1;
				}

				if(header.number_of_variable_length_records!=0)
				{
					if(header.vlrs==null)
					{
						error=string.Format("number_of_variable_length_records is {0} but vlrs pointer is zero", header.number_of_variable_length_records);
						return 1;
					}

					for(int i=0; i<header.number_of_variable_length_records; i++)
					{
						vlrs_size+=54;
						if(header.vlrs[i].record_length_after_header!=0)
						{
							if(header.vlrs==null)
							{
								error=string.Format("vlrs[{0}].record_length_after_header is {1} but vlrs[{0}].data pointer is zero", i, header.vlrs[i].record_length_after_header);
								return 1;
							}
							vlrs_size+=header.vlrs[i].record_length_after_header;
						}
					}
				}

				if((vlrs_size+header.header_size+header.user_data_after_header_size)!=header.offset_to_point_data)
				{
					error=string.Format("header_size ({0}) plus vlrs_size ({1}) plus user_data_after_header_size ({2}) does not equal offset_to_point_data ({3})", header.header_size, vlrs_size, header.user_data_after_header_size, header.offset_to_point_data);
					return 1;
				}

				LASzip laszip=null;
				try
				{
					laszip=new LASzip();
				}
				catch
				{
					error="could not alloc LASzip";
					return 1;
				}

				if(!laszip.setup(header.point_data_format, header.point_data_record_length, LASzip.COMPRESSOR_NONE))
				{
					error=string.Format("invalid combination of point_data_format {0} and point_data_record_length {1}", header.point_data_format, header.point_data_record_length);
					return 1;
				}

				#region create point's item pointers
				for(uint i=0; i<laszip.num_items; i++)
				{
					switch(laszip.items[i].type)
					{
						case LASitem.Type.POINT14:
						case LASitem.Type.POINT10:
						case LASitem.Type.GPSTIME11:
						case LASitem.Type.RGBNIR14:
						case LASitem.Type.RGB12:
						case LASitem.Type.WAVEPACKET13: break;
						case LASitem.Type.BYTE:
							point.num_extra_bytes=laszip.items[i].size;
							point.extra_bytes=new byte[point.num_extra_bytes];
							break;
						default:
							error=string.Format("unknown LASitem type {0}", laszip.items[i].type);
							return 1;
					}
				}
				#endregion

				uint laszip_vrl_payload_size=0;

				if(compress)
				{
					if(!laszip.setup(header.point_data_format, header.point_data_record_length, LASzip.COMPRESSOR_DEFAULT))
					{
						error=string.Format("cannot compress point_data_format {0} with point_data_record_length {1}", header.point_data_format, header.point_data_record_length);
						return 1;
					}
					laszip.request_version(2);
					laszip_vrl_payload_size=34u+6u*laszip.num_items;
				}
				else
				{
					laszip.request_version(0);
				}
				#endregion

				#region open the file
				try
				{
					streamout=new FileStream(file_name, FileMode.Create, FileAccess.Write, FileShare.Read);
				}
				catch
				{
					error=string.Format("cannot open file '{0}'", file_name);
					return 1;
				}
				#endregion

				#region write the header variable after variable
				try
				{
					streamout.WriteByte((byte)'L');
					streamout.WriteByte((byte)'A');
					streamout.WriteByte((byte)'S');
					streamout.WriteByte((byte)'F');
				}
				catch
				{
					error="writing header.file_signature";
					return 1;
				}

				try { streamout.Write(BitConverter.GetBytes(header.file_source_ID), 0, 2); }
				catch { error="writing header.file_source_ID"; return 1; }

				try { streamout.Write(BitConverter.GetBytes(header.global_encoding), 0, 2); }
				catch { error="writing header.global_encoding"; return 1; }

				try { streamout.Write(BitConverter.GetBytes(header.project_ID_GUID_data_1), 0, 4); }
				catch { error="writing header.project_ID_GUID_data_1"; return 1; }

				try { streamout.Write(BitConverter.GetBytes(header.project_ID_GUID_data_2), 0, 2); }
				catch { error="writing header.project_ID_GUID_data_2"; return 1; }

				try { streamout.Write(BitConverter.GetBytes(header.project_ID_GUID_data_3), 0, 2); }
				catch { error="writing header.project_ID_GUID_data_3"; return 1; }

				try { streamout.Write(header.project_ID_GUID_data_4, 0, 8); }
				catch { error="writing header.project_ID_GUID_data_4"; return 1; }

				try { streamout.WriteByte(header.version_major); }
				catch { error="writing header.version_major"; return 1; }

				try { streamout.WriteByte(header.version_minor); }
				catch { error="writing header.version_minor"; return 1; }

				try { streamout.Write(header.system_identifier, 0, 32); }
				catch { error="writing header.system_identifier"; return 1; }

				byte[] generatingSoftware=Encoding.ASCII.GetBytes(string.Format("LASzip DLL {0}.{1} r{2} ({3})", LASzip.VERSION_MAJOR, LASzip.VERSION_MINOR, LASzip.VERSION_REVISION, LASzip.VERSION_BUILD_DATE));
				Array.Copy(generatingSoftware, header.generating_software, Math.Min(generatingSoftware.Length, 32));
				try { streamout.Write(header.generating_software, 0, 32); }
				catch { error="writing header.generating_software"; return 1; }

				try { streamout.Write(BitConverter.GetBytes(header.file_creation_day), 0, 2); }
				catch { error="writing header.file_creation_day"; return 1; }

				try { streamout.Write(BitConverter.GetBytes(header.file_creation_year), 0, 2); }
				catch { error="writing header.file_creation_year"; return 1; }

				try { streamout.Write(BitConverter.GetBytes(header.header_size), 0, 2); }
				catch { error="writing header.header_size"; return 1; }

				if(compress) header.offset_to_point_data+=(54+laszip_vrl_payload_size);

				try { streamout.Write(BitConverter.GetBytes(header.offset_to_point_data), 0, 4); }
				catch { error="writing header.offset_to_point_data"; return 1; }

				if(compress)
				{
					header.offset_to_point_data-=(54+laszip_vrl_payload_size);
					header.number_of_variable_length_records+=1;
				}

				try { streamout.Write(BitConverter.GetBytes(header.number_of_variable_length_records), 0, 4); }
				catch { error="writing header.number_of_variable_length_records"; return 1; }

				if(compress)
				{
					header.number_of_variable_length_records-=1;
					header.point_data_format|=128;
				}

				try { streamout.WriteByte(header.point_data_format); }
				catch { error="writing header.point_data_format"; return 1; }

				if(compress) header.point_data_format&=127;

				try { streamout.Write(BitConverter.GetBytes(header.point_data_record_length), 0, 2); }
				catch { error="writing header.point_data_record_length"; return 1; }

				try { streamout.Write(BitConverter.GetBytes(header.number_of_point_records), 0, 4); }
				catch { error="writing header.number_of_point_records"; return 1; }

				for(uint i=0; i<5; i++)
				{
					try { streamout.Write(BitConverter.GetBytes(header.number_of_points_by_return[i]), 0, 4); }
					catch { error=string.Format("writing header.number_of_points_by_return {0}", i); return 1; }
				}

				try { streamout.Write(BitConverter.GetBytes(header.x_scale_factor), 0, 8); }
				catch { error="writing header.x_scale_factor"; return 1; }

				try { streamout.Write(BitConverter.GetBytes(header.y_scale_factor), 0, 8); }
				catch { error="writing header.y_scale_factor"; return 1; }

				try { streamout.Write(BitConverter.GetBytes(header.z_scale_factor), 0, 8); }
				catch { error="writing header.z_scale_factor"; return 1; }

				try { streamout.Write(BitConverter.GetBytes(header.x_offset), 0, 8); }
				catch { error="writing header.x_offset"; return 1; }

				try { streamout.Write(BitConverter.GetBytes(header.y_offset), 0, 8); }
				catch { error="writing header.y_offset"; return 1; }

				try { streamout.Write(BitConverter.GetBytes(header.z_offset), 0, 8); }
				catch { error="writing header.z_offset"; return 1; }

				try { streamout.Write(BitConverter.GetBytes(header.max_x), 0, 8); }
				catch { error="writing header.max_x"; return 1; }

				try { streamout.Write(BitConverter.GetBytes(header.min_x), 0, 8); }
				catch { error="writing header.min_x"; return 1; }

				try { streamout.Write(BitConverter.GetBytes(header.max_y), 0, 8); }
				catch { error="writing header.max_y"; return 1; }

				try { streamout.Write(BitConverter.GetBytes(header.min_y), 0, 8); }
				catch { error="writing header.min_y"; return 1; }

				try { streamout.Write(BitConverter.GetBytes(header.max_z), 0, 8); }
				catch { error="writing header.max_z"; return 1; }

				try { streamout.Write(BitConverter.GetBytes(header.min_z), 0, 8); }
				catch { error="writing header.min_z"; return 1; }

				#region special handling for LAS 1.3+
				if(header.version_major==1&&header.version_minor>=3)
				{
					if(header.header_size<235)
					{
						error=string.Format("for LAS 1.{0} header_size should at least be 235 but it is only {1}", header.version_minor, header.header_size);
						return 1;
					}

					try { streamout.Write(BitConverter.GetBytes(header.start_of_waveform_data_packet_record), 0, 8); }
					catch { error="writing header.start_of_waveform_data_packet_record"; return 1; }

					header.user_data_in_header_size=header.header_size-235u;
				}
				else header.user_data_in_header_size=header.header_size-227u;
				#endregion

				#region special handling for LAS 1.4+
				if(header.version_major==1&&header.version_minor>=4)
				{
					if(header.header_size<375)
					{
						error=string.Format("for LAS 1.{0} header_size should at least be 375 but it is only {1}", header.version_minor, header.header_size);
						return 1;
					}

					try { streamout.Write(BitConverter.GetBytes(header.start_of_first_extended_variable_length_record), 0, 8); }
					catch { error="writing header.start_of_first_extended_variable_length_record"; return 1; }

					try { streamout.Write(BitConverter.GetBytes(header.number_of_extended_variable_length_records), 0, 4); }
					catch { error="writing header.number_of_extended_variable_length_records"; return 1; }

					try { streamout.Write(BitConverter.GetBytes(header.extended_number_of_point_records), 0, 8); }
					catch { error="writing header.extended_number_of_point_records"; return 1; }

					for(uint i=0; i<15; i++)
					{
						try { streamout.Write(BitConverter.GetBytes(header.extended_number_of_points_by_return[i]), 0, 8); }
						catch { error=string.Format("writing header.extended_number_of_points_by_return[{0}]", i); return 1; }
					}

					header.user_data_in_header_size=header.header_size-375u;
				}
				#endregion

				#region write any number of user-defined bytes that might have been added to the header
				if(header.user_data_in_header_size!=0)
				{
					try { streamout.Write(header.user_data_in_header, 0, (int)header.user_data_in_header_size); }
					catch { error=string.Format("writing {0} bytes of data into header.user_data_in_header", header.user_data_in_header_size); return 1; }
				}
				#endregion

				#region write variable length records into the header
				if(header.number_of_variable_length_records!=0)
				{
					for(int i=0; i<header.number_of_variable_length_records; i++)
					{
						// write variable length records variable after variable (to avoid alignment issues)
						try { streamout.Write(BitConverter.GetBytes(header.vlrs[i].reserved), 0, 2); }
						catch { error=string.Format("writing header.vlrs[{0}].reserved", i); return 1; }

						try { streamout.Write(header.vlrs[i].user_id, 0, 16); }
						catch { error=string.Format("writing header.vlrs[{0}].user_id", i); return 1; }

						try { streamout.Write(BitConverter.GetBytes(header.vlrs[i].record_id), 0, 2); }
						catch { error=string.Format("writing header.vlrs[{0}].record_id", i); return 1; }

						try { streamout.Write(BitConverter.GetBytes(header.vlrs[i].record_length_after_header), 0, 2); }
						catch { error=string.Format("writing header.vlrs[{0}].record_length_after_header", i); return 1; }

						try { streamout.Write(header.vlrs[i].description, 0, 32); }
						catch { error=string.Format("writing header.vlrs[{0}].description", i); return 1; }

						// write data following the header of the variable length record
						if(header.vlrs[i].record_length_after_header!=0)
						{
							try { streamout.Write(header.vlrs[i].data, 0, header.vlrs[i].record_length_after_header); }
							catch { error=string.Format("writing {0} bytes of data into header.vlrs[{1}].data", header.vlrs[i].record_length_after_header, i); return 1; }
						}
					}
				}

				if(compress)
				{
					#region write the LASzip VLR header
					uint i=header.number_of_variable_length_records;

					ushort reserved=0xAABB;
					try { streamout.Write(BitConverter.GetBytes(reserved), 0, 2); }
					catch { error=string.Format("writing header.vlrs[{0}].reserved", i); return 1; }

					byte[] user_id1=Encoding.ASCII.GetBytes("laszip encoded");
					byte[] user_id=new byte[16];
					Array.Copy(user_id1, user_id, Math.Min(16, user_id1.Length));
					try { streamout.Write(user_id, 0, 16); }
					catch { error=string.Format("writing header.vlrs[{0}].user_id", i); return 1; }

					ushort record_id=22204;
					try { streamout.Write(BitConverter.GetBytes(record_id), 0, 2); }
					catch { error=string.Format("writing header.vlrs[{0}].record_id", i); return 1; }

					ushort record_length_after_header=(ushort)laszip_vrl_payload_size;
					try { streamout.Write(BitConverter.GetBytes(record_length_after_header), 0, 2); }
					catch { error=string.Format("writing header.vlrs[{0}].record_length_after_header", i); return 1; }

					byte[] description1=Encoding.ASCII.GetBytes(string.Format("LASzip DLL {0}.{1} r{2} ({3})", LASzip.VERSION_MAJOR, LASzip.VERSION_MINOR, LASzip.VERSION_REVISION, LASzip.VERSION_BUILD_DATE));
					byte[] description=new byte[32];

					try { streamout.Write(description, 0, 32); }
					catch { error=string.Format("writing header.vlrs[{0}].description", i); return 1; }

					// write the LASzip VLR payload

					//     U16  compressor                2 bytes
					//     U32  coder                     2 bytes
					//     U8   version_major             1 byte
					//     U8   version_minor             1 byte
					//     U16  version_revision          2 bytes
					//     U32  options                   4 bytes
					//     I32  chunk_size                4 bytes
					//     I64  number_of_special_evlrs   8 bytes
					//     I64  offset_to_special_evlrs   8 bytes
					//     U16  num_items                 2 bytes
					//        U16 type                2 bytes * num_items
					//        U16 size                2 bytes * num_items
					//        U16 version             2 bytes * num_items
					// which totals 34+6*num_items

					try { streamout.Write(BitConverter.GetBytes(laszip.compressor), 0, 2); }
					catch { error=string.Format("writing compressor {0}", laszip.compressor); return 1; }

					try { streamout.Write(BitConverter.GetBytes(laszip.coder), 0, 2); }
					catch { error=string.Format("writing coder {0}", laszip.coder); return 1; }

					try { streamout.WriteByte(laszip.version_major); }
					catch { error=string.Format("writing version_major {0}", laszip.version_major); return 1; }

					try { streamout.WriteByte(laszip.version_minor); }
					catch { error=string.Format("writing version_minor {0}", laszip.version_minor); return 1; }

					try { streamout.Write(BitConverter.GetBytes(laszip.version_revision), 0, 2); }
					catch { error=string.Format("writing version_revision {0}", laszip.version_revision); return 1; }

					try { streamout.Write(BitConverter.GetBytes(laszip.options), 0, 4); }
					catch { error=string.Format("writing options {0}", laszip.options); return 1; }

					try { streamout.Write(BitConverter.GetBytes(laszip.chunk_size), 0, 4); }
					catch { error=string.Format("writing chunk_size {0}", laszip.chunk_size); return 1; }

					try { streamout.Write(BitConverter.GetBytes(laszip.number_of_special_evlrs), 0, 8); }
					catch { error=string.Format("writing number_of_special_evlrs {0}", laszip.number_of_special_evlrs); return 1; }

					try { streamout.Write(BitConverter.GetBytes(laszip.offset_to_special_evlrs), 0, 8); }
					catch { error=string.Format("writing offset_to_special_evlrs {0}", laszip.offset_to_special_evlrs); return 1; }

					try { streamout.Write(BitConverter.GetBytes(laszip.num_items), 0, 2); }
					catch { error=string.Format("writing num_items {0}", laszip.num_items); return 1; }

					for(uint j=0; j<laszip.num_items; j++)
					{
						ushort type=(ushort)laszip.items[j].type;
						try { streamout.Write(BitConverter.GetBytes(type), 0, 2); }
						catch { error=string.Format("writing type {0} of item {1}", laszip.items[j].type, j); return 1; }

						try { streamout.Write(BitConverter.GetBytes(laszip.items[j].size), 0, 2); }
						catch { error=string.Format("writing size {0} of item {1}", laszip.items[j].size, j); return 1; }

						try { streamout.Write(BitConverter.GetBytes(laszip.items[j].version), 0, 2); }
						catch { error=string.Format("writing version {0} of item {1}", laszip.items[j].version, j); return 1; }
					}
					#endregion
				}
				#endregion

				#region write any number of user-defined bytes that might have been added after the header
				if(header.user_data_after_header_size!=0)
				{
					try { streamout.Write(header.user_data_after_header, 0, (int)header.user_data_after_header_size); }
					catch { error=string.Format("writing {0} bytes of data into header.user_data_after_header", header.user_data_after_header_size); return 1; }
				}
				#endregion

				#endregion

				#region create the point writer
				try { writer=new LASwritePoint(); }
				catch { error="could not alloc LASwritePoint"; return 1; }

				if(!writer.setup(laszip.num_items, laszip.items, laszip))
				{
					error="setup of LASwritePoint failed";
					return 1;
				}

				if(!writer.init(streamout))
				{
					error="init of LASwritePoint failed";
					return 1;
				}
				#endregion

				// set the point number and point count
				npoints=header.number_of_point_records;
				p_count=0;
			}
			catch
			{
				error=string.Format("internal error in laszip_open_writer '{0}'", file_name);
				return 1;
			}

			error=null;
			return 0;
		}
Example #2
0
        public int laszip_open_reader(Stream stream, ref bool is_compressed)
		{
            if (stream == null)
            {
                error = "file stream is empty";
                return 1;
            }

            streamin = stream;

			try
			{
				byte[] buffer=new byte[32];

				#region read the header variable after variable
				if(streamin.Read(buffer, 0, 4)!=4)
				{
					error="reading header.file_signature";
					return 1;
				}

				if(buffer[0]!='L'&&buffer[1]!='A'&&buffer[2]!='S'&&buffer[3]!='F')
				{
					error="wrong file_signature. not a LAS/LAZ file.";
					return 1;
				}

				if(streamin.Read(buffer, 0, 2)!=2)
				{
					error="reading header.file_source_ID";
					return 1;
				}
				header.file_source_ID=BitConverter.ToUInt16(buffer, 0);

				if(streamin.Read(buffer, 0, 2)!=2)
				{
					error="reading header.global_encoding";
					return 1;
				}
				header.global_encoding=BitConverter.ToUInt16(buffer, 0);

				if(streamin.Read(buffer, 0, 4)!=4)
				{
					error="reading header.project_ID_GUID_data_1";
					return 1;
				}
				header.project_ID_GUID_data_1=BitConverter.ToUInt32(buffer, 0);

				if(streamin.Read(buffer, 0, 2)!=2)
				{
					error="reading header.project_ID_GUID_data_2";
					return 1;
				}
				header.project_ID_GUID_data_2=BitConverter.ToUInt16(buffer, 0);

				if(streamin.Read(buffer, 0, 2)!=2)
				{
					error="reading header.project_ID_GUID_data_3";
					return 1;
				}
				header.project_ID_GUID_data_3=BitConverter.ToUInt16(buffer, 0);

				if(streamin.Read(header.project_ID_GUID_data_4, 0, 8)!=8)
				{
					error="reading header.project_ID_GUID_data_4";
					return 1;
				}

				if(streamin.Read(buffer, 0, 1)!=1)
				{
					error="reading header.version_major";
					return 1;
				}
				header.version_major=buffer[0];

				if(streamin.Read(buffer, 0, 1)!=1)
				{
					error="reading header.version_minor";
					return 1;
				}
				header.version_minor=buffer[0];

				if(streamin.Read(header.system_identifier, 0, 32)!=32)
				{
					error="reading header.system_identifier";
					return 1;
				}

				if(streamin.Read(header.generating_software, 0, 32)!=32)
				{
					error="reading header.generating_software";
					return 1;
				}

				if(streamin.Read(buffer, 0, 2)!=2)
				{
					error="reading header.file_creation_day";
					return 1;
				}
				header.file_creation_day=BitConverter.ToUInt16(buffer, 0);

				if(streamin.Read(buffer, 0, 2)!=2)
				{
					error="reading header.file_creation_year";
					return 1;
				}
				header.file_creation_year=BitConverter.ToUInt16(buffer, 0);

				if(streamin.Read(buffer, 0, 2)!=2)
				{
					error="reading header.header_size";
					return 1;
				}
				header.header_size=BitConverter.ToUInt16(buffer, 0);

				if(streamin.Read(buffer, 0, 4)!=4)
				{
					error="reading header.offset_to_point_data";
					return 1;
				}
				header.offset_to_point_data=BitConverter.ToUInt32(buffer, 0);

				if(streamin.Read(buffer, 0, 4)!=4)
				{
					error="reading header.number_of_variable_length_records";
					return 1;
				}
				header.number_of_variable_length_records=BitConverter.ToUInt32(buffer, 0);

				if(streamin.Read(buffer, 0, 1)!=1)
				{
					error="reading header.point_data_format";
					return 1;
				}
				header.point_data_format=buffer[0];

				if(streamin.Read(buffer, 0, 2)!=2)
				{
					error="reading header.point_data_record_length";
					return 1;
				}
				header.point_data_record_length=BitConverter.ToUInt16(buffer, 0);

				if(streamin.Read(buffer, 0, 4)!=4)
				{
					error="reading header.number_of_point_records";
					return 1;
				}
				header.number_of_point_records=BitConverter.ToUInt32(buffer, 0);

				for(int i=0; i<5; i++)
				{
					if(streamin.Read(buffer, 0, 4)!=4)
					{
						error=string.Format("reading header.number_of_points_by_return {0}", i);
						return 1;
					}
					header.number_of_points_by_return[i]=BitConverter.ToUInt32(buffer, 0);
				}

				if(streamin.Read(buffer, 0, 8)!=8)
				{
					error="reading header.x_scale_factor";
					return 1;
				}
				header.x_scale_factor=BitConverter.ToDouble(buffer, 0);

				if(streamin.Read(buffer, 0, 8)!=8)
				{
					error="reading header.y_scale_factor";
					return 1;
				}
				header.y_scale_factor=BitConverter.ToDouble(buffer, 0);

				if(streamin.Read(buffer, 0, 8)!=8)
				{
					error="reading header.z_scale_factor";
					return 1;
				}
				header.z_scale_factor=BitConverter.ToDouble(buffer, 0);

				if(streamin.Read(buffer, 0, 8)!=8)
				{
					error="reading header.x_offset";
					return 1;
				}
				header.x_offset=BitConverter.ToDouble(buffer, 0);

				if(streamin.Read(buffer, 0, 8)!=8)
				{
					error="reading header.y_offset";
					return 1;
				}
				header.y_offset=BitConverter.ToDouble(buffer, 0);

				if(streamin.Read(buffer, 0, 8)!=8)
				{
					error="reading header.z_offset";
					return 1;
				}
				header.z_offset=BitConverter.ToDouble(buffer, 0);

				if(streamin.Read(buffer, 0, 8)!=8)
				{
					error="reading header.max_x";
					return 1;
				}
				header.max_x=BitConverter.ToDouble(buffer, 0);

				if(streamin.Read(buffer, 0, 8)!=8)
				{
					error="reading header.min_x";
					return 1;
				}
				header.min_x=BitConverter.ToDouble(buffer, 0);

				if(streamin.Read(buffer, 0, 8)!=8)
				{
					error="reading header.max_y";
					return 1;
				}
				header.max_y=BitConverter.ToDouble(buffer, 0);

				if(streamin.Read(buffer, 0, 8)!=8)
				{
					error="reading header.min_y";
					return 1;
				}
				header.min_y=BitConverter.ToDouble(buffer, 0);

				if(streamin.Read(buffer, 0, 8)!=8)
				{
					error="reading header.max_z";
					return 1;
				}
				header.max_z=BitConverter.ToDouble(buffer, 0);

				if(streamin.Read(buffer, 0, 8)!=8)
				{
					error="reading header.min_z";
					return 1;
				}
				header.min_z=BitConverter.ToDouble(buffer, 0);

				// special handling for LAS 1.3
				if((header.version_major==1)&&(header.version_minor>=3))
				{
					if(header.header_size<235)
					{
						error=string.Format("for LAS 1.{0} header_size should at least be 235 but it is only {1}", header.version_minor, header.header_size);
						return 1;
					}
					else
					{
						if(streamin.Read(buffer, 0, 8)!=8)
						{
							error="reading header.start_of_waveform_data_packet_record";
							return 1;
						}
						header.start_of_waveform_data_packet_record=BitConverter.ToUInt64(buffer, 0);
						header.user_data_in_header_size=(uint)header.header_size-235;
					}
				}
				else
				{
					header.user_data_in_header_size=(uint)header.header_size-227;
				}

				// special handling for LAS 1.4
				if((header.version_major==1)&&(header.version_minor>=4))
				{
					if(header.header_size<375)
					{
						error=string.Format("for LAS 1.{0} header_size should at least be 375 but it is only {1}", header.version_minor, header.header_size);
						return 1;
					}
					else
					{
						if(streamin.Read(buffer, 0, 8)!=8)
						{
							error="reading header.start_of_first_extended_variable_length_record";
							return 1;
						}
						header.start_of_first_extended_variable_length_record=BitConverter.ToUInt64(buffer, 0);

						if(streamin.Read(buffer, 0, 4)!=4)
						{
							error="reading header.number_of_extended_variable_length_records";
							return 1;
						}
						header.number_of_extended_variable_length_records=BitConverter.ToUInt32(buffer, 0);

						if(streamin.Read(buffer, 0, 8)!=8)
						{
							error="reading header.extended_number_of_point_records";
							return 1;
						}
						header.extended_number_of_point_records=BitConverter.ToUInt64(buffer, 0);

						for(int i=0; i<15; i++)
						{
							if(streamin.Read(buffer, 0, 8)!=8)
							{
								error=string.Format("reading header.extended_number_of_points_by_return[{0}]", i);
								return 1;
							}
							header.extended_number_of_points_by_return[i]=BitConverter.ToUInt64(buffer, 0);
						}
						header.user_data_in_header_size=(uint)header.header_size-375;
					}
				}

				// load any number of user-defined bytes that might have been added to the header
				if(header.user_data_in_header_size!=0)
				{
					header.user_data_in_header=new byte[header.user_data_in_header_size];

					if(streamin.Read(header.user_data_in_header, 0, (int)header.user_data_in_header_size)!=header.user_data_in_header_size)
					{
						error=string.Format("reading {0} bytes of data into header.user_data_in_header", header.user_data_in_header_size);
						return 1;
					}
				}
				#endregion

				#region read variable length records into the header
				uint vlrs_size=0;
				LASzip laszip=null;

				if(header.number_of_variable_length_records!=0)
				{
					header.vlrs=new List<laszip_vlr>();

					for(int i=0; i<header.number_of_variable_length_records; i++)
					{
						header.vlrs.Add(new laszip_vlr());

						// make sure there are enough bytes left to read a variable length record before the point block starts
						if(((int)header.offset_to_point_data-vlrs_size-header.header_size)<54)
						{
							warning=string.Format("only {0} bytes until point block after reading {1} of {2} vlrs. skipping remaining vlrs ...", (int)header.offset_to_point_data-vlrs_size-header.header_size, i, header.number_of_variable_length_records);
							header.number_of_variable_length_records=(uint)i;
							break;
						}

						// read variable length records variable after variable (to avoid alignment issues)
						if(streamin.Read(buffer, 0, 2)!=2)
						{
							error=string.Format("reading header.vlrs[{0}].reserved", i);
							return 1;
						}
						header.vlrs[i].reserved=BitConverter.ToUInt16(buffer, 0);

						if(streamin.Read(header.vlrs[i].user_id, 0, 16)!=16)
						{
							error=string.Format("reading header.vlrs[{0}].user_id", i);
							return 1;
						}

						if(streamin.Read(buffer, 0, 2)!=2)
						{
							error=string.Format("reading header.vlrs[{0}].record_id", i);
							return 1;
						}
						header.vlrs[i].record_id=BitConverter.ToUInt16(buffer, 0);

						if(streamin.Read(buffer, 0, 2)!=2)
						{
							error=string.Format("reading header.vlrs[{0}].record_length_after_header", i);
							return 1;
						}
						header.vlrs[i].record_length_after_header=BitConverter.ToUInt16(buffer, 0);

						if(streamin.Read(header.vlrs[i].description, 0, 32)!=32)
						{
							error=string.Format("reading header.vlrs[{0}].description", i);
							return 1;
						}

						// keep track on the number of bytes we have read so far
						vlrs_size+=54;

						// check variable length record contents
						if(header.vlrs[i].reserved!=0xAABB)
						{
							warning=string.Format("wrong header.vlrs[{0}].reserved: {1} != 0xAABB", i, header.vlrs[i].reserved);
						}

						// make sure there are enough bytes left to read the data of the variable length record before the point block starts
						if(((int)header.offset_to_point_data-vlrs_size-header.header_size)<header.vlrs[i].record_length_after_header)
						{
							warning=string.Format("only {0} bytes until point block when trying to read {1} bytes into header.vlrs[{2}].data", (int)header.offset_to_point_data-vlrs_size-header.header_size, header.vlrs[i].record_length_after_header, i);
							header.vlrs[i].record_length_after_header=(ushort)(header.offset_to_point_data-vlrs_size-header.header_size);
						}

						string userid="";
						for(int a=0; a<header.vlrs[i].user_id.Length; a++)
						{
							if(header.vlrs[i].user_id[a]==0) break;
							userid+=(char)header.vlrs[i].user_id[a];
						}

						// load data following the header of the variable length record
						if(header.vlrs[i].record_length_after_header!=0)
						{
							if(userid=="laszip encoded")
							{
								laszip=new LASzip();

								// read the LASzip VLR payload

								//     U16  compressor                2 bytes 
								//     U32  coder                     2 bytes 
								//     U8   version_major             1 byte 
								//     U8   version_minor             1 byte
								//     U16  version_revision          2 bytes
								//     U32  options                   4 bytes 
								//     I32  chunk_size                4 bytes
								//     I64  number_of_special_evlrs   8 bytes
								//     I64  offset_to_special_evlrs   8 bytes
								//     U16  num_items                 2 bytes
								//        U16 type                2 bytes * num_items
								//        U16 size                2 bytes * num_items
								//        U16 version             2 bytes * num_items
								// which totals 34+6*num_items

								if(streamin.Read(buffer, 0, 2)!=2)
								{
									error="reading compressor";
									return 1;
								}
								laszip.compressor=BitConverter.ToUInt16(buffer, 0);

								if(streamin.Read(buffer, 0, 2)!=2)
								{
									error="reading coder";
									return 1;
								}
								laszip.coder=BitConverter.ToUInt16(buffer, 0);

								if(streamin.Read(buffer, 0, 1)!=1)
								{
									error="reading version_major";
									return 1;
								}
								laszip.version_major=buffer[0];

								if(streamin.Read(buffer, 0, 1)!=1)
								{
									error="reading version_minor";
									return 1;
								}
								laszip.version_minor=buffer[0];

								if(streamin.Read(buffer, 0, 2)!=2)
								{
									error="reading version_revision";
									return 1;
								}
								laszip.version_revision=BitConverter.ToUInt16(buffer, 0);

								if(streamin.Read(buffer, 0, 4)!=4)
								{
									error="reading options";
									return 1;
								}
								laszip.options=BitConverter.ToUInt32(buffer, 0);

								if(streamin.Read(buffer, 0, 4)!=4)
								{
									error="reading chunk_size";
									return 1;
								}
								laszip.chunk_size=BitConverter.ToUInt32(buffer, 0);

								if(streamin.Read(buffer, 0, 8)!=8)
								{
									error="reading number_of_special_evlrs";
									return 1;
								}
								laszip.number_of_special_evlrs=BitConverter.ToInt64(buffer, 0);

								if(streamin.Read(buffer, 0, 8)!=8)
								{
									error="reading offset_to_special_evlrs";
									return 1;
								}
								laszip.offset_to_special_evlrs=BitConverter.ToInt64(buffer, 0);

								if(streamin.Read(buffer, 0, 2)!=2)
								{
									error="reading num_items";
									return 1;
								}
								laszip.num_items=BitConverter.ToUInt16(buffer, 0);

								laszip.items=new LASitem[laszip.num_items];
								for(int j=0; j<laszip.num_items; j++)
								{
									laszip.items[j]=new LASitem();

									if(streamin.Read(buffer, 0, 2)!=2)
									{
										error=string.Format("reading type of item {0}", j);
										return 1;
									}
									laszip.items[j].type=(LASitem.Type)BitConverter.ToUInt16(buffer, 0);

									if(streamin.Read(buffer, 0, 2)!=2)
									{
										error=string.Format("reading size of item {0}", j);
										return 1;
									}
									laszip.items[j].size=BitConverter.ToUInt16(buffer, 0);

									if(streamin.Read(buffer, 0, 2)!=2)
									{
										error=string.Format("reading version of item {0}", j);
										return 1;
									}
									laszip.items[j].version=BitConverter.ToUInt16(buffer, 0);
								}
							}
							else
							{
								header.vlrs[i].data=new byte[header.vlrs[i].record_length_after_header];
								if(streamin.Read(header.vlrs[i].data, 0, header.vlrs[i].record_length_after_header)!=header.vlrs[i].record_length_after_header)
								{
									error=string.Format("reading {0} bytes of data into header.vlrs[{1}].data", header.vlrs[i].record_length_after_header, i);
									return 1;
								}
							}
						}
						else
						{
							header.vlrs[i].data=null;
						}

						// keep track on the number of bytes we have read so far
						vlrs_size+=header.vlrs[i].record_length_after_header;

						// special handling for LASzip VLR
						if(userid=="laszip encoded")
						{
							// we take our the VLR for LASzip away
							header.offset_to_point_data-=(uint)(54+header.vlrs[i].record_length_after_header);
							vlrs_size-=(uint)(54+header.vlrs[i].record_length_after_header);
							header.vlrs.RemoveAt(i);
							i--;
							header.number_of_variable_length_records--;
						}
					}
				}
				#endregion

				// load any number of user-defined bytes that might have been added after the header
				header.user_data_after_header_size=header.offset_to_point_data-vlrs_size-header.header_size;
				if(header.user_data_after_header_size!=0)
				{
					header.user_data_after_header=new byte[header.user_data_after_header_size];

					if(streamin.Read(header.user_data_after_header, 0, (int)header.user_data_after_header_size)!=header.user_data_after_header_size)
					{
						error=string.Format("reading {0} bytes of data into header.user_data_after_header", header.user_data_after_header_size);
						return 1;
					}
				}

				// remove extra bits in point data type
				if((header.point_data_format&128)!=0||(header.point_data_format&64)!=0)
				{
					if(laszip==null)
					{
						error="this file was compressed with an experimental version of LASzip. contact '*****@*****.**' for assistance";
						return 1;
					}
					header.point_data_format&=127;
				}

				// check if file is compressed
				if(laszip!=null)
				{
					// yes. check the compressor state
					is_compressed=true;
					if(!laszip.check())
					{
						error=string.Format("{0} upgrade to the latest release of LAStools (with LASzip) or contact '*****@*****.**' for assistance", laszip.get_error());
						return 1;
					}
				}
				else
				{
					// no. setup an un-compressed read
					is_compressed=false;
					laszip=new LASzip();
					if(!laszip.setup(header.point_data_format, header.point_data_record_length, LASzip.COMPRESSOR_NONE))
					{
						error=string.Format("invalid combination of point_data_format {0} and point_data_record_length {1}", header.point_data_format, header.point_data_record_length);
						return 1;
					}
				}

				// create point's item pointers
				for(int i=0; i<laszip.num_items; i++)
				{
					switch(laszip.items[i].type)
					{
						case LASitem.Type.POINT14:
						case LASitem.Type.POINT10:
						case LASitem.Type.GPSTIME11:
						case LASitem.Type.RGBNIR14:
						case LASitem.Type.RGB12:
						case LASitem.Type.WAVEPACKET13:
							break;
						case LASitem.Type.BYTE:
							point.num_extra_bytes=laszip.items[i].size;
							point.extra_bytes=new byte[point.num_extra_bytes];
							break;
						default:
							error=string.Format("unknown LASitem type {0}", laszip.items[i].type);
							return 1;
					}
				}

				// create the point reader
				reader=new LASreadPoint();
				if(!reader.setup(laszip.num_items, laszip.items, laszip))
				{
					error="setup of LASreadPoint failed";
					return 1;
				}

				if(!reader.init(streamin))
				{
					error="init of LASreadPoint failed";
					return 1;
				}

				laszip=null;

				// set the point number and point count
				npoints=header.number_of_point_records;
				p_count=0;
			}
			catch
			{
				error="internal error in laszip_open_reader";
				return 1;
			}

			error=null;
			return 0;
		}