﻿

#include "geoprojectionconverter.hpp"
#include "lasreader.hpp"
#include "laszip_decompress_selective_v3.hpp"
#include "lasutility.hpp"
#include "laswriter.hpp"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#ifdef _WIN32
#include <windows.h>
#endif

static const char * LASpointClassification [32] = {
  "never classified",
  "unclassified",
  "ground",
  "low vegetation",
  "medium vegetation",
  "high vegetation",
  "building",
  "noise",
  "keypoint",
  "water",
  "rail",
  "road surface",
  "overlap",
  "wire guard",
  "wire conductor",
  "tower",
  "wire connector",
  "bridge deck",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition"
};

void usage(bool error=false, bool wait=false)
{
  fprintf(stderr,"usage:\n");
  fprintf(stderr,"lasinfo -i lidar.las\n");
  fprintf(stderr,"lasinfo -i lidar.las -compute_density -o lidar_info.txt\n");
  fprintf(stderr,"lasinfo -i *.las\n");
  fprintf(stderr,"lasinfo -i *.las -single -otxt\n");
  fprintf(stderr,"lasinfo -no_header -no_vlrs -i lidar.laz\n");
  fprintf(stderr,"lasinfo -nv -nc -stdout -i lidar.las\n");
  fprintf(stderr,"lasinfo -nv -nc -stdout -i *.laz -single | grep version\n");
  fprintf(stderr,"lasinfo -i *.laz -subseq 100000 100100 -histo user_data 8\n");
  fprintf(stderr,"lasinfo -i *.las -repair\n");
  fprintf(stderr,"lasinfo -i *.laz -repair_bb -set_file_creation 8 2007\n");
  fprintf(stderr,"lasinfo -i *.las -repair_counters -set_version 1.2\n");
  fprintf(stderr,"lasinfo -i *.laz -set_system_identifier \"hello world!\" -set_generating_software \"this is a test (-:\"\n");
  if (wait)
  {
    fprintf(stderr,"<press ENTER>\n");
    getc(stdin);
  }
  exit(error);
}

static void byebye(bool error=false, bool wait=false)
{
  if (wait)
  {
    fprintf(stderr,"<press ENTER>\n");
    getc(stdin);
  }
  exit(error);
}

static inline void VecUpdateMinMax3dv(double min[3], double max[3], const double v[3])
{
  if (v[0]<min[0]) min[0]=v[0]; else if (v[0]>max[0]) max[0]=v[0];
  if (v[1]<min[1]) min[1]=v[1]; else if (v[1]>max[1]) max[1]=v[1];
  if (v[2]<min[2]) min[2]=v[2]; else if (v[2]>max[2]) max[2]=v[2];
}

static inline void VecCopy3dv(double v[3], const double a[3])
{
  v[0] = a[0];
  v[1] = a[1];
  v[2] = a[2];
}

static int lidardouble2string(char* string, double value)
{
  int len;
  len = sprintf(string, "%.15f", value) - 1;
  while (string[len] == '0') len--;
  if (string[len] != '.') len++;
  string[len] = '\0';
  return len;
}

static I32 lidardouble2string(char* string, double value, double precision)
{
  if (precision == 0.1)
    sprintf(string, "%.1f", value);
  else if (precision == 0.01)
    sprintf(string, "%.2f", value);
  else if (precision == 0.001 || precision == 0.002 || precision == 0.005 || precision == 0.025) 
    sprintf(string, "%.3f", value);
  else if (precision == 0.0001 || precision == 0.0002 || precision == 0.0005 || precision == 0.0025)
    sprintf(string, "%.4f", value);
  else if (precision == 0.00001 || precision == 0.00002 || precision == 0.00005 || precision == 0.00025)
    sprintf(string, "%.5f", value);
  else if (precision == 0.000001)
    sprintf(string, "%.6f", value);
  else if (precision == 0.0000001)
    sprintf(string, "%.7f", value);
  else if (precision == 0.00000001)
    sprintf(string, "%.8f", value);
  else
    return lidardouble2string(string, value);
  return (I32)strlen(string)-1;
}

static bool valid_resolution(F64 coordinate, F64 offset, F64 scale_factor)
{
  F64 coordinate_without_offset = coordinate - offset;
  F64 fixed_precision_multiplier = coordinate_without_offset / scale_factor;
  I64 quantized_fixed_precision_multiplier = I64_QUANTIZE(fixed_precision_multiplier);
  if ((fabs(fixed_precision_multiplier - quantized_fixed_precision_multiplier)) < 0.001)
  {
    return true;
  }
  return false;
}

#ifdef COMPILE_WITH_GUI
extern int lasinfo_gui(int argc, char *argv[], LASreadOpener* lasreadopener);
#endif

#ifdef COMPILE_WITH_MULTI_CORE
extern int lasinfo_multi_core(int argc, char *argv[], LASreadOpener* lasreadopener, LAShistogram* lashistogram, LASwriteOpener* laswriteopener, int cores, BOOL cpu64);
#endif

int main(int argc, char *argv[])
{
  int i;
#ifdef COMPILE_WITH_GUI
  bool gui = false;
#endif
#ifdef COMPILE_WITH_MULTI_CORE
  I32 cores = 1;
  BOOL cpu64 = FALSE;
#endif
  bool wait = false;
  bool verbose = false;
  bool no_header = false;
  bool no_variable_header = false;
  bool no_returns = false;
  bool no_min_max = false;
  bool no_warnings = false;
  bool check_points = true;
  bool compute_density = false;
  bool gps_week = false;
  bool check_outside = true;
  bool report_outside = false;
  bool suppress_z = false;
  bool suppress_classification = false;
  bool suppress_flags = false;
  bool suppress_intensity = false;
  bool suppress_user_data = false;
  bool suppress_point_source = false;
  bool suppress_scan_angle = false;
  bool suppress_RGB = false;
  bool suppress_extra_bytes = false;
  bool repair_bb = false;
  bool repair_counters = false;
    bool edit_header = false;
    I32 set_file_source_ID = -1;
  bool set_file_source_ID_from_point_source_ID = false;
  I32 set_global_encoding = -1;
  I64 set_project_ID_GUID_data_1 = -1;
  I32 set_project_ID_GUID_data_2 = -1;
  I32 set_project_ID_GUID_data_3 = -1;
  I32 set_project_ID_GUID_data_4a = -1;
  I64 set_project_ID_GUID_data_4b = -1;
  I8 set_version_major = -1;
  I8 set_version_minor = -1;
	I8* set_system_identifier = 0;
	I8* set_generating_software = 0;
	I32 set_creation_day = -1;
	I32 set_creation_year = -1;
  U16 set_header_size = 0;
  U32 set_offset_to_point_data = 0;
  I32 set_number_of_variable_length_records = -1;
  I32 set_point_data_format = -1;
  I32 set_point_data_record_length = -1;
  I32 set_number_of_point_records = -1;
  I32 set_number_of_points_by_return[5] = {-1, -1, -1, -1, -1};
  F64* set_bounding_box = 0;
  F64* set_offset = 0;
  F64* set_scale = 0;
  I64 set_start_of_waveform_data_packet_record = -1;
  bool auto_date_creation = false;
  FILE* file_out = stderr;
  U32 horizontal_units = 0; 

  I64 subsequence_start = 0;
  I64 subsequence_stop = I64_MAX;
  U32 progress = 0;

  LAShistogram lashistogram;
  LASreadOpener lasreadopener;
  GeoProjectionConverter geoprojectionconverter;
  LASwriteOpener laswriteopener;

  if (argc == 1)
  {
#ifdef COMPILE_WITH_GUI
    return lasinfo_gui(argc, argv, 0);
#else
    fprintf(stderr,"%s is better run in the command line\n", argv[0]);
    char file_name[256];
    fprintf(stderr,"enter input file: "); fgets(file_name, 256, stdin);
    file_name[strlen(file_name)-1] = '\0';
    lasreadopener.set_file_name(file_name);
#endif
  }
  else
  {
    for (i = 1; i < argc; i++)
    {
        if (argv[i][0] == '') argv[i][0] = '-';
    }
    if (!lashistogram.parse(argc, argv)) byebye(true);
    if (!lasreadopener.parse(argc, argv)) byebye(true);
    if (!geoprojectionconverter.parse(argc, argv)) byebye(true);
    if (!laswriteopener.parse(argc, argv)) byebye(true);
  }

  if (laswriteopener.is_piped())
  {
    file_out = stdout;
  }

  for (i = 1; i < argc; i++)
  {
    if (argv[i][0] == '\0')
    {
      continue;
    }
    else if (strcmp(argv[i],"-h") == 0)
    {
      fprintf(stderr, "LAStools (by martin@rapidlasso.com) version %d\n", LAS_TOOLS_VERSION);
      usage();
    }
    else if (strcmp(argv[i],"-v") == 0)
    {
      verbose = true;
    }
    else if (strcmp(argv[i],"-version") == 0)
    {
      fprintf(stderr, "LAStools (by martin@rapidlasso.com) version %d\n", LAS_TOOLS_VERSION);
      byebye();
    }
    else if (strcmp(argv[i],"-wait") == 0)
    {
      wait = true;
    }
    else if (strcmp(argv[i],"-gui") == 0)
    {
#ifdef COMPILE_WITH_GUI
      gui = true;
#else
      fprintf(stderr, "WARNING: not compiled with GUI support. ignoring '-gui' ...\n");
#endif
    }
    else if (strcmp(argv[i],"-cores") == 0)
    {
#ifdef COMPILE_WITH_MULTI_CORE
      if ((i+1) >= argc)
      {
        fprintf(stderr,"ERROR: '%s' needs 1 argument: number\n", argv[i]);
        usage(true);
      }
      argv[i][0] = '\0';
      i++;
      cores = atoi(argv[i]);
      argv[i][0] = '\0';
#else
      fprintf(stderr, "WARNING: not compiled with multi-core batching. ignoring '-cores' ...\n");
      i++;
#endif
    }
    else if (strcmp(argv[i],"-cpu64") == 0)
    {
#ifdef COMPILE_WITH_MULTI_CORE
      cpu64 = TRUE;
#else
      fprintf(stderr, "WARNING: not compiled with 64 bit support. ignoring '-cpu64' ...\n");
#endif
      argv[i][0] = '\0';
    }
    else if (strcmp(argv[i],"-quiet") == 0)
    {
      file_out = 0;
    }
    else if (strcmp(argv[i],"-otxt") == 0)
    {
      laswriteopener.set_appendix("_info");
      laswriteopener.set_format("txt");
    }
    else if (strcmp(argv[i],"-nh") == 0 || strcmp(argv[i],"-no_header") == 0)
    {
      no_header = true;
    }
    else if (strcmp(argv[i],"-nv") == 0 || strcmp(argv[i],"-no_vlrs") == 0)
    {
      no_variable_header = true;
    }
    else if (strcmp(argv[i],"-nr") == 0 || strcmp(argv[i],"-no_returns") == 0)
    {
      no_returns = true;
    }
    else if (strcmp(argv[i],"-nmm") == 0 || strcmp(argv[i],"-no_min_max") == 0)
    {
      no_min_max = true;
    }
    else if (strcmp(argv[i],"-nw") == 0 || strcmp(argv[i],"-no_warnings") == 0)
    {
      no_warnings = true;
    }
    else if (strcmp(argv[i],"-nc") == 0 || strcmp(argv[i],"-no_check") == 0)
    {
      check_points = false;
    }
    else if (strcmp(argv[i],"-cd") == 0 || strcmp(argv[i],"-compute_density") == 0)
    {
      compute_density = true;
    }
    else if (strcmp(argv[i],"-gw") == 0 || strcmp(argv[i],"-gps_week") == 0)
    {
      gps_week = true;
    }
    else if (strcmp(argv[i],"-nco") == 0 || strcmp(argv[i],"-no_check_outside") == 0)
    {
      check_outside = false;
    }
    else if (strcmp(argv[i],"-ro") == 0 || strcmp(argv[i],"-report_outside") == 0)
    {
      report_outside = true;
      check_outside = true;
    }
    else if (strcmp(argv[i],"-subseq") == 0)
    {
      if ((i+2) >= argc)
      {
        fprintf(stderr,"ERROR: '%s' needs 2 arguments: start stop\n", argv[i]);
        byebye(true);
      }
#ifdef _WIN32
      if (sscanf(argv[i+1], "%I64d", &subsequence_start) != 1)
#else
      if (sscanf(argv[i+1], "%lld", &subsequence_start) != 1)
#endif
      {
        fprintf(stderr,"ERROR: '%s' needs 2 arguments: start stop but '%s' is not a valid start\n", argv[i], argv[i+1]);
        byebye(true);
      }
      if (subsequence_start < 0)
      {
#ifdef _WIN32
        fprintf(stderr,"ERROR: '%s' needs 2 arguments: start stop but '%I64d' is not a valid start\n", argv[i], subsequence_start);
#else
        fprintf(stderr,"ERROR: '%s' needs 2 arguments: start stop but '%lld' is not a valid start\n", argv[i], subsequence_start);
#endif
        byebye(true);
      }
#ifdef _WIN32
      if (sscanf(argv[i+2], "%I64d", &subsequence_stop) != 1)
#else
      if (sscanf(argv[i+2], "%lld", &subsequence_stop) != 1)
#endif
      {
        fprintf(stderr,"ERROR: '%s' needs 2 arguments: start stop but '%s' is not a valid stop\n", argv[i], argv[i+2]);
        byebye(true);
      }
      if (subsequence_stop < 0)
      {
#ifdef _WIN32
        fprintf(stderr,"ERROR: '%s' needs 2 arguments: start stop but '%I64d' is not a valid stop\n", argv[i], subsequence_stop);
#else
        fprintf(stderr,"ERROR: '%s' needs 2 arguments: start stop but '%lld' is not a valid stop\n", argv[i], subsequence_stop);
#endif
        byebye(true);
      }
      if (subsequence_start >= subsequence_stop)
      {
#ifdef _WIN32
        fprintf(stderr,"ERROR: '%s' needs 2 arguments: start stop but '%I64d' and '%I64d' are no valid start and stop combination \n", argv[i], subsequence_start, subsequence_stop);
#else
        fprintf(stderr,"ERROR: '%s' needs 2 arguments: start stop but '%lld' and '%lld' are no valid start and stop combination \n", argv[i], subsequence_start, subsequence_stop);
#endif
        byebye(true);
      }
      i+=2;
    }
    else if (strcmp(argv[i],"-start_at_point") == 0)
    {
      if ((i+1) >= argc)
      {
        fprintf(stderr,"ERROR: '%s' needs 1 argument: start\n", argv[i]);
        byebye(true);
      }
#ifdef _WIN32
      if (sscanf(argv[i+1], "%I64d", &subsequence_start) != 1)
#else
      if (sscanf(argv[i+1], "%lld", &subsequence_start) != 1)
#endif
      {
        fprintf(stderr,"ERROR: '%s' needs 1 argument: start but '%s' is not a valid start\n", argv[i], argv[i+1]);
        byebye(true);
      }
      if (subsequence_start < 0)
      {
#ifdef _WIN32
        fprintf(stderr,"ERROR: '%s' needs 1 argument: start but '%I64d' is not a valid start\n", argv[i], subsequence_start);
#else
        fprintf(stderr,"ERROR: '%s' needs 1 argument: start but '%lld' is not a valid start\n", argv[i], subsequence_start);
#endif
        byebye(true);
      }
      i+=1;
    }
    else if (strcmp(argv[i],"-stop_at_point") == 0)
    {
      if ((i+1) >= argc)
      {
        fprintf(stderr,"ERROR: '%s' needs 1 argument: stop\n", argv[i]);
        byebye(true);
      }
#ifdef _WIN32
      if (sscanf(argv[i+1], "%I64d", &subsequence_stop) != 1)
#else
      if (sscanf(argv[i+1], "%lld", &subsequence_stop) != 1)
#endif
      {
        fprintf(stderr,"ERROR: '%s' needs 1 argument: start but '%s' is not a valid stop\n", argv[i], argv[i+1]);
        byebye(true);
      }
      if (subsequence_stop < 0)
      {
#ifdef _WIN32
        fprintf(stderr,"ERROR: '%s' needs 1 argument: start but '%I64d' is not a valid stop\n", argv[i], subsequence_stop);
#else
        fprintf(stderr,"ERROR: '%s' needs 1 argument: start but '%lld' is not a valid stop\n", argv[i], subsequence_stop);
#endif
        byebye(true);
      }
      i+=1;
    } else if (strcmp(argv[i], "-repair") == 0) {
        repair_bb = true;
        repair_counters = true;
    } else if (strcmp(argv[i], "-repair_bb") == 0) {
        repair_bb = true;
    } else if (strcmp(argv[i], "-repair_counters") == 0) {
        repair_counters = true;
    }
    else if (strcmp(argv[i],"-auto_date") == 0 || strcmp(argv[i],"-auto_creation_date") == 0 || strcmp(argv[i],"-auto_creation") == 0)
    {
      auto_date_creation = true;
    } else if (strcmp(argv[i], "-set_file_source_ID") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: index\n", argv[i]);
            byebye(true);
        }
        i++;
        set_file_source_ID = atoi(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_file_source_ID_from_point_source_ID") == 0) {
        set_file_source_ID_from_point_source_ID = true;
        edit_header = true;
    } else if (strcmp(argv[i], "-set_GUID") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: value1\n", argv[i]);
            byebye(true);
        }
        i++;
#ifdef _WIN32
        if (sscanf(argv[i], "%I64x-%x-%x-%x-%I64x", &set_project_ID_GUID_data_1, &set_project_ID_GUID_data_2, &set_project_ID_GUID_data_3, &set_project_ID_GUID_data_4a, &set_project_ID_GUID_data_4b) != 5)
#else
        if (sscanf(argv[i], "%llx-%x-%x-%x-%llx", &set_project_ID_GUID_data_1, &set_project_ID_GUID_data_2,
                   &set_project_ID_GUID_data_3, &set_project_ID_GUID_data_4a, &set_project_ID_GUID_data_4b) != 5)
#endif
        {
            if ((i + 1) >= argc) {
                fprintf(stderr, "ERROR: '%s' needs hexadecimal GUID in 'F794F8A4-A23E-421E-A134-ACF7754E1C54' format\n",
                        argv[i]);
                byebye(true);
            }
        }
        edit_header = true;
    } else if (strcmp(argv[i], "-set_system_identifier") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: name\n", argv[i]);
            byebye(true);
        }
        i++;
        set_system_identifier = new I8[32];
        memset(set_system_identifier, 0, 32);
        strncpy(set_system_identifier, argv[i], 32);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_generating_software") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: name\n", argv[i]);
            byebye(true);
        }
        i++;
        set_generating_software = new I8[32];
        memset(set_generating_software, 0, 32);
        strncpy(set_generating_software, argv[i], 32);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_bb") == 0 || strcmp(argv[i], "-set_bounding_box") == 0) {
        if ((i + 6) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 6 arguments: min_x min_y min_z max_x max_y max_z\n", argv[i]);
            byebye(true);
        }
        set_bounding_box = new F64[6];
        i++;
        set_bounding_box[1] = atof(argv[i]);
        i++;
        set_bounding_box[3] = atof(argv[i]);
        i++;
        set_bounding_box[5] = atof(argv[i]);
        i++;
        set_bounding_box[0] = atof(argv[i]);
        i++;
        set_bounding_box[2] = atof(argv[i]);
        i++;
        set_bounding_box[4] = atof(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_offset") == 0) {
        if ((i + 3) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 3 arguments: x y z\n", argv[i]);
            byebye(true);
        }
        set_offset = new F64[3];
        i++;
        set_offset[0] = atof(argv[i]);
        i++;
        set_offset[1] = atof(argv[i]);
        i++;
        set_offset[2] = atof(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_scale") == 0) {
        if ((i + 3) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 3 arguments: x y z\n", argv[i]);
            byebye(true);
        }
        set_scale = new F64[3];
        i++;
        set_scale[0] = atof(argv[i]);
        i++;
        set_scale[1] = atof(argv[i]);
        i++;
        set_scale[2] = atof(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_global_encoding") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: number\n", argv[i]);
            byebye(true);
        }
        i++;
        set_global_encoding = atoi(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_version") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: major.minor\n", argv[i]);
            byebye(true);
        }
        i++;
        int major;
        int minor;
        if (sscanf(argv[i], "%d.%d", &major, &minor) != 2) {
            fprintf(stderr, "ERROR: cannot understand argument '%s' of '%s'\n", argv[i], argv[i - 1]);
            usage();
        }
        set_version_major = (I8) major;
        set_version_minor = (I8) minor;
        edit_header = true;
    } else if (strcmp(argv[i], "-set_creation_date") == 0 || strcmp(argv[i], "-set_file_creation") == 0) {
        if ((i + 2) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 2 arguments: day year\n", argv[i]);
            byebye(true);
        }
        i++;
        set_creation_day = (U16) atoi(argv[i]);
        i++;
        set_creation_year = (U16) atoi(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_number_of_point_records") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: number\n", argv[i]);
            byebye(true);
        }
        i++;
        set_number_of_point_records = atoi(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_number_of_points_by_return") == 0) {
        if ((i + 5) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 5 arguments: ret1 ret2 ret3 ret4 ret5\n", argv[i]);
            byebye(true);
        }
        i++;
        set_number_of_points_by_return[0] = atoi(argv[i]);
        i++;
        set_number_of_points_by_return[1] = atoi(argv[i]);
        i++;
        set_number_of_points_by_return[2] = atoi(argv[i]);
        i++;
        set_number_of_points_by_return[3] = atoi(argv[i]);
        i++;
        set_number_of_points_by_return[4] = atoi(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_header_size") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: size\n", argv[i]);
            byebye(true);
        }
        i++;
        set_header_size = atoi(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_offset_to_point_data") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: offset\n", argv[i]);
            byebye(true);
        }
        i++;
        set_offset_to_point_data = atoi(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_number_of_variable_length_records") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: number\n", argv[i]);
            byebye(true);
        }
        i++;
        set_number_of_variable_length_records = atoi(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_point_data_format") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: type\n", argv[i]);
            byebye(true);
        }
        i++;
        set_point_data_format = atoi(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_point_data_record_length") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: size\n", argv[i]);
            byebye(true);
        }
        i++;
        set_point_data_record_length = atoi(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_start_of_waveform_data_packet_record") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: start\n", argv[i]);
            byebye(true);
        }
        i++;
        set_start_of_waveform_data_packet_record = atoi(argv[i]);
        edit_header = true;
    } else if ((strncmp(argv[i], "-suppress_", 10) == 0))
    {
      if (strcmp(argv[i],"-suppress_z") == 0)
      {
        suppress_z = true;
      }
      else if (strcmp(argv[i],"-suppress_classification") == 0)
      {
        suppress_classification = true;
      }
      else if (strcmp(argv[i],"-suppress_flags") == 0)
      {
        suppress_flags = true;
      }
      else if (strcmp(argv[i],"-suppress_intensity") == 0)
      {
        suppress_intensity = true;
      }
      else if (strcmp(argv[i],"-suppress_user_data") == 0)
      {
        suppress_user_data = true;
      }
      else if (strcmp(argv[i],"-suppress_point_source") == 0)
      {
        suppress_point_source = true;
      }
      else if (strcmp(argv[i],"-suppress_scan_angle") == 0)
      {
        suppress_scan_angle = true;
      }
      else if (strcmp(argv[i],"-suppress_RGB") == 0)
      {
        suppress_RGB = true;
      }
      else if (strcmp(argv[i],"-suppress_extra_bytes") == 0)
      {
        suppress_extra_bytes = true;
      }
      else
      {
        fprintf(stderr, "ERROR: cannot understand argument '%s'\n", argv[i]);
        byebye(TRUE);
      }
    }
    else if (strcmp(argv[i],"-progress") == 0)
    {
      if ((i+1) >= argc)
      {
        fprintf(stderr,"ERROR: '%s' needs 1 argument: every\n", argv[i]);
        byebye(true);
      }
			i++;
        progress = atoi(argv[i]);
    }
    else if ((argv[i][0] != '-') && (lasreadopener.get_file_name_number() == 0))
    {
      lasreadopener.add_file_name(argv[i]);
      argv[i][0] = '\0';
    }
    else
    {
      fprintf(stderr, "ERROR: cannot understand argument '%s'\n", argv[i]);
      byebye(true);
    }
  }

#ifdef COMPILE_WITH_GUI
  if (gui)
  {
    return lasinfo_gui(argc, argv, &lasreadopener);
  }
#endif

#ifdef COMPILE_WITH_MULTI_CORE
  if (cores > 1)
  {
    if (lasreadopener.get_file_name_number() < 2)
    {
      fprintf(stderr,"WARNING: only %u input files. ignoring '-cores %d' ...\n", lasreadopener.get_file_name_number(), cores);
    }
    else if (lasreadopener.is_merged())
    {
      fprintf(stderr,"WARNING: input files merged on-the-fly. ignoring '-cores %d' ...\n", cores);
    }
    else
    {
      return lasinfo_multi_core(argc, argv, &lasreadopener, &lashistogram, &laswriteopener, cores, cpu64);
    }
  }
  if (cpu64)
  {
    return lasinfo_multi_core(argc, argv, &lasreadopener, &lashistogram, &laswriteopener, 1, TRUE);
  }
#endif

  if (!lasreadopener.active())
  {
    fprintf (stderr, "ERROR: no input specified\n");
    byebye(true, argc==1);
  }

  U32 decompress_selective = LASZIP_DECOMPRESS_SELECTIVE_ALL;

  if (suppress_z)
  {
    decompress_selective &= ~LASZIP_DECOMPRESS_SELECTIVE_Z;
  }

  if (suppress_classification)
  {
    decompress_selective &= ~LASZIP_DECOMPRESS_SELECTIVE_CLASSIFICATION;
  }

  if (suppress_flags)
  {
    decompress_selective &= ~LASZIP_DECOMPRESS_SELECTIVE_FLAGS;
  }

  if (suppress_intensity)
  {
    decompress_selective &= ~LASZIP_DECOMPRESS_SELECTIVE_INTENSITY;
  }

  if (suppress_user_data)
  {
    decompress_selective &= ~LASZIP_DECOMPRESS_SELECTIVE_USER_DATA;
  }

  if (suppress_point_source)
  {
    decompress_selective &= ~LASZIP_DECOMPRESS_SELECTIVE_POINT_SOURCE;
  }

  if (suppress_scan_angle)
  {
    decompress_selective &= ~LASZIP_DECOMPRESS_SELECTIVE_SCAN_ANGLE;
  }

  if (suppress_RGB)
  {
    decompress_selective &= ~LASZIP_DECOMPRESS_SELECTIVE_RGB;
  }

  if (suppress_extra_bytes)
  {
    decompress_selective &= ~LASZIP_DECOMPRESS_SELECTIVE_EXTRA_BYTES;
  }

  lasreadopener.set_decompress_selective(decompress_selective);

  while (lasreadopener.active())
  {
    if (edit_header)
    {
      if (lasreadopener.is_piped())
      {
        fprintf(stderr, "ERROR: cannot edit header of piped input\n");
        edit_header = false;
      }
      else if (lasreadopener.is_merged())
      {
        fprintf(stderr, "ERROR: cannot edit header of merged input\n");
        edit_header = false;
      }
      else if (lasreadopener.is_buffered())
      {
        fprintf(stderr, "ERROR: cannot edit header of buffered input\n");
        edit_header = false;
      }
      const CHAR* file_name = lasreadopener.get_file_name(lasreadopener.get_file_name_current());
      if ((strstr(file_name, ".laz") == 0) && (strstr(file_name, ".las") == 0) && (strstr(file_name, ".LAZ") == 0) && (strstr(file_name, ".LAS") == 0))
      {
        fprintf(stderr, "ERROR: can only edit for LAS or LAZ files, not for '%s'\n", file_name);
        edit_header = false;
      }
      if (set_file_source_ID_from_point_source_ID)
      {
        LASreader* lasreader = lasreadopener.open(file_name, FALSE);
        if (lasreader == 0)
        {
          fprintf(stderr, "ERROR: cannot open lasreader for '%s'\n", file_name);
          byebye(true, argc==1);
        }
        if (lasreader->read_point())
        {
          set_file_source_ID = lasreader->point.get_point_source_ID();
        }
        else
        {
          set_file_source_ID = -1;
        }
        lasreader->close();
        delete lasreader;
      }
      FILE* file = fopen(file_name, "rb+");
      if (file == 0)
      {
        fprintf (stderr, "ERROR: could not open file '%s' for edit of header\n", file_name);
        edit_header = false;
      }
      else if (edit_header)
      {
        if (set_file_source_ID != -1)
        {
          U16 file_source_ID = U16_CLAMP(set_file_source_ID);
          fseek(file, 4, SEEK_SET);
          fwrite(&file_source_ID, sizeof(U16), 1, file);
        }
        if (set_global_encoding != -1)
        {
          U16 global_encoding = U16_CLAMP(set_global_encoding);
          fseek(file, 6, SEEK_SET);
          fwrite(&global_encoding, sizeof(U16), 1, file);
        }
        if (set_project_ID_GUID_data_1 != -1)
        {
          fseek(file, 8, SEEK_SET);
          U32 GUID_data_1 = U32_CLAMP(set_project_ID_GUID_data_1);
          U16 GUID_data_2 = U16_CLAMP(set_project_ID_GUID_data_2);
          U16 GUID_data_3 = U16_CLAMP(set_project_ID_GUID_data_3);
          U16 GUID_data_4a = U16_CLAMP(set_project_ID_GUID_data_4a);
          U16 GUID_data_4b_a = U16_CLAMP(set_project_ID_GUID_data_4b >> 32);
          U32 GUID_data_4b_b = U32_CLAMP(set_project_ID_GUID_data_4b & 0xFFFFFFFF);
          fwrite(&GUID_data_1, sizeof(U32), 1, file);
          fwrite(&GUID_data_2, sizeof(U16), 1, file);
          fwrite(&GUID_data_3, sizeof(U16), 1, file);
          fwrite(&GUID_data_4a, sizeof(U16), 1, file);
          fwrite(&GUID_data_4b_a, sizeof(U16), 1, file);
          fwrite(&GUID_data_4b_b, sizeof(U32), 1, file);
        }
        if (set_version_major != -1)
        {
          fseek(file, 24, SEEK_SET);
          fwrite(&set_version_major, sizeof(I8), 1, file);
        }
        if (set_version_minor != -1)
        {
          fseek(file, 25, SEEK_SET);
          fwrite(&set_version_minor, sizeof(I8), 1, file);
        }
        if (set_system_identifier)
        {
          fseek(file, 26, SEEK_SET);
          fwrite(set_system_identifier, sizeof(I8), 32, file);
        }
        if (set_generating_software)
        {
          fseek(file, 58, SEEK_SET);
          fwrite(set_generating_software, sizeof(I8), 32, file);
        }
        if (set_creation_day != -1)
        {
          U16 creation_day = U16_CLAMP(set_creation_day);
          fseek(file, 90, SEEK_SET);
          fwrite(&creation_day, sizeof(U16), 1, file);
        }
        if (set_creation_year != -1)
        {
          U16 creation_year = U16_CLAMP(set_creation_year);
          fseek(file, 92, SEEK_SET);
          fwrite(&creation_year, sizeof(U16), 1, file);
        }
        if (set_header_size)
        {
          fseek(file, 94, SEEK_SET);
          fwrite(&set_header_size, sizeof(U16), 1, file);
        }
        if (set_offset_to_point_data)
        {
          fseek(file, 96, SEEK_SET);
          fwrite(&set_offset_to_point_data, sizeof(U32), 1, file);
        }
        if (set_number_of_variable_length_records != -1)
        {
          fseek(file, 100, SEEK_SET);
          fwrite(&set_number_of_variable_length_records, sizeof(U32), 1, file);
        }
        if (set_point_data_format != -1)
        {
          U8 point_data_format = U8_CLAMP(set_point_data_format);
          fseek(file, 104, SEEK_SET);
          fwrite(&point_data_format, sizeof(U8), 1, file);
        }
        if (set_point_data_record_length != -1)
        {
          U16 point_data_record_length = U16_CLAMP(set_point_data_record_length);
          fseek(file, 105, SEEK_SET);
          fwrite(&point_data_record_length, sizeof(U16), 1, file);
        }
        if (set_number_of_point_records != -1)
        {
          fseek(file, 107, SEEK_SET);
          fwrite(&set_number_of_point_records, sizeof(I32), 1, file);
        }
        if (set_number_of_points_by_return[0] != -1)
        {
          fseek(file, 111, SEEK_SET);
          fwrite(&(set_number_of_points_by_return[0]), sizeof(I32), 1, file);
        }
        if (set_number_of_points_by_return[1] != -1)
        {
          fseek(file, 115, SEEK_SET);
          fwrite(&(set_number_of_points_by_return[1]), sizeof(I32), 1, file);
        }
        if (set_number_of_points_by_return[2] != -1)
        {
          fseek(file, 119, SEEK_SET);
          fwrite(&(set_number_of_points_by_return[2]), sizeof(I32), 1, file);
        }
        if (set_number_of_points_by_return[3] != -1)
        {
          fseek(file, 123, SEEK_SET);
          fwrite(&(set_number_of_points_by_return[3]), sizeof(I32), 1, file);
        }
        if (set_number_of_points_by_return[4] != -1)
        {
          fseek(file, 127, SEEK_SET);
          fwrite(&(set_number_of_points_by_return[4]), sizeof(I32), 1, file);
        }
        if (set_scale)
        {
          fseek(file, 131, SEEK_SET);
          fwrite(set_scale, 3*sizeof(F64), 1, file);
        }
        if (set_offset)
        {
          fseek(file, 155, SEEK_SET);
          fwrite(set_offset, 3*sizeof(F64), 1, file);
        }
        if (set_bounding_box)
        {
          fseek(file, 179, SEEK_SET);
          fwrite(set_bounding_box, 6*sizeof(F64), 1, file);
        }
        if (set_start_of_waveform_data_packet_record != -1)
        {
          fseek(file, 227, SEEK_SET);
          fwrite(&set_start_of_waveform_data_packet_record, sizeof(I64), 1, file);
        }
        if (verbose) fprintf(stderr, "edited '%s' ...\n", file_name);
        fclose(file);
      }
    }

    LASreader* lasreader = lasreadopener.open();
    if (lasreader == 0)
    {
      fprintf(stderr, "ERROR: cannot open lasreader\n");
      byebye(true, argc==1);
    }

    LASheader* lasheader = &lasreader->header;

#ifdef _WIN32
    if (verbose) fprintf(stderr, "%s '%s' with %I64d points\n", (repair_bb || repair_counters ? "repairing" : "reading"), (lasreadopener.get_file_name() ? lasreadopener.get_file_name() : "stdin"), lasreader->npoints);
#else
    if (verbose) fprintf(stderr, "%s '%s' with %lld points\n", (repair_bb || repair_counters ? "repairing" : "reading"), (lasreadopener.get_file_name() ? lasreadopener.get_file_name() : "stdin"), lasreader->npoints);
#endif

    if (auto_date_creation && lasreadopener.get_file_name())
    {
#ifdef _WIN32
      WIN32_FILE_ATTRIBUTE_DATA attr;
	    SYSTEMTIME creation;
      GetFileAttributesEx(lasreadopener.get_file_name(), GetFileExInfoStandard, &attr);
	    FileTimeToSystemTime(&attr.ftCreationTime, &creation);
      int startday[13] = {-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
      set_creation_day = startday[creation.wMonth] + creation.wDay;
      set_creation_year = creation.wYear;

      if ((((creation.wYear)%4) == 0) && (creation.wMonth > 2)) set_creation_day++;
      edit_header = true;
#endif
    }

    if (laswriteopener.get_file_name() == 0)
    {
      if (lasreadopener.get_file_name() && (laswriteopener.get_format() == LAS_TOOLS_FORMAT_TXT))
      {
        laswriteopener.make_file_name(lasreadopener.get_file_name(), -2);
      }
    }

    if (laswriteopener.get_file_name())
    {

      if (lasreadopener.get_file_name() && (strcmp(lasreadopener.get_file_name(), laswriteopener.get_file_name()) == 0))
      {
        fprintf(stderr, "ERROR: input and output file name for '%s' are identical\n", lasreadopener.get_file_name());
        usage(true);
      }

      file_out = fopen(laswriteopener.get_file_name(), "w");
      if (file_out == 0)
      {
        fprintf (stderr, "WARNING: could not open output text file '%s'\n", laswriteopener.get_file_name());
        file_out = stderr;
      }
    }

    if (file_out)
    {
      if (lasreadopener.is_merged())
      {
        fprintf(file_out, "lasinfo (%u) report for %u merged files\012", LAS_TOOLS_VERSION, lasreadopener.get_file_name_number());
      }
      else if (lasreadopener.is_piped())
      {
        fprintf(file_out, "lasinfo (%u) report for piped input\012", LAS_TOOLS_VERSION);
      }
      else if (lasreadopener.get_file_name())
      {
        fprintf(file_out, "lasinfo (%u) report for '%s'\012", LAS_TOOLS_VERSION, lasreadopener.get_file_name());
      }
    }

    U32 number_of_point_records = lasheader->number_of_point_records;
    U32 number_of_points_by_return0 = lasheader->number_of_points_by_return[0];

    CHAR printstring[4096];

    if (file_out && !no_header)
    {
      if (lasreadopener.is_merged() && (lasreader->header.version_minor < 4))
      {
#ifdef _WIN32
        if (lasreader->npoints > number_of_point_records) fprintf(file_out, "WARNING: merged file has %I64d points, more than the 32 bits counters of LAS 1.%d can handle.\012", lasreader->npoints, lasreader->header.version_minor);
#else
        if (lasreader->npoints > number_of_point_records) fprintf(file_out, "WARNING: merged file has %lld points, more than the 32 bits counters of LAS 1.%d can handle.\012", lasreader->npoints, lasreader->header.version_minor);
#endif
      }
      fprintf(file_out, "reporting all LAS header entries:\012");
      fprintf(file_out, "  file signature:             '%.4s'\012", lasheader->file_signature);
      fprintf(file_out, "  file source ID:             %d\012", lasheader->file_source_ID);
      fprintf(file_out, "  global_encoding:            %d\012", lasheader->global_encoding);
      fprintf(file_out, "  project ID GUID data 1-4:   %08X-%04X-%04X-%04X-%04X%08X\012", lasheader->project_ID_GUID_data_1, lasheader->project_ID_GUID_data_2, lasheader->project_ID_GUID_data_3, *((U16*)(lasheader->project_ID_GUID_data_4)), *((U16*)(lasheader->project_ID_GUID_data_4+2)), *((U32*)(lasheader->project_ID_GUID_data_4+4)));
      fprintf(file_out, "  version major.minor:        %d.%d\012", lasheader->version_major, lasheader->version_minor);
      fprintf(file_out, "  system identifier:          '%.32s'\012", lasheader->system_identifier);
      fprintf(file_out, "  generating software:        '%.32s'\012", lasheader->generating_software);
      fprintf(file_out, "  file creation day/year:     %d/%d\012", lasheader->file_creation_day, lasheader->file_creation_year);
      fprintf(file_out, "  header size:                %d\012", lasheader->header_size);
      fprintf(file_out, "  offset to point data:       %u\012", lasheader->offset_to_point_data);
      fprintf(file_out, "  number var. length records: %u\012", lasheader->number_of_variable_length_records);
      fprintf(file_out, "  point data format:          %d\012", lasheader->point_data_format);
      fprintf(file_out, "  point data record length:   %d\012", lasheader->point_data_record_length);
      fprintf(file_out, "  number of point records:    %u\012", lasheader->number_of_point_records);
      fprintf(file_out, "  number of points by return: %u %u %u %u %u\012", lasheader->number_of_points_by_return[0], lasheader->number_of_points_by_return[1], lasheader->number_of_points_by_return[2], lasheader->number_of_points_by_return[3], lasheader->number_of_points_by_return[4]);
      fprintf(file_out, "  scale factor x y z:         "); lidardouble2string(printstring, lasheader->x_scale_factor); fprintf(file_out, "%s ", printstring);  lidardouble2string(printstring, lasheader->y_scale_factor); fprintf(file_out, "%s ", printstring);  lidardouble2string(printstring, lasheader->z_scale_factor); fprintf(file_out, "%s\012", printstring);
      fprintf(file_out, "  offset x y z:               "); lidardouble2string(printstring, lasheader->x_offset); fprintf(file_out, "%s ", printstring);  lidardouble2string(printstring, lasheader->y_offset); fprintf(file_out, "%s ", printstring);  lidardouble2string(printstring, lasheader->z_offset); fprintf(file_out, "%s\012", printstring);
      fprintf(file_out, "  min x y z:                  "); lidardouble2string(printstring, lasheader->min_x, lasheader->x_scale_factor); fprintf(file_out, "%s ", printstring); lidardouble2string(printstring, lasheader->min_y, lasheader->y_scale_factor); fprintf(file_out, "%s ", printstring); lidardouble2string(printstring, lasheader->min_z, lasheader->z_scale_factor); fprintf(file_out, "%s\012", printstring);
      fprintf(file_out, "  max x y z:                  "); lidardouble2string(printstring, lasheader->max_x, lasheader->x_scale_factor); fprintf(file_out, "%s ", printstring); lidardouble2string(printstring, lasheader->max_y, lasheader->y_scale_factor); fprintf(file_out, "%s ", printstring); lidardouble2string(printstring, lasheader->max_z, lasheader->z_scale_factor); fprintf(file_out, "%s\012", printstring);
      if (!no_warnings && !valid_resolution(lasheader->min_x, lasheader->x_offset, lasheader->x_scale_factor))
      {
        fprintf(file_out, "WARNING: stored resolution of min_x not compatible with x_offset and x_scale_factor: "); lidardouble2string(printstring, lasheader->min_x); fprintf(file_out, "%s\n", printstring);
      }
      if (!no_warnings && !valid_resolution(lasheader->min_y, lasheader->y_offset, lasheader->y_scale_factor))
      {
        fprintf(file_out, "WARNING: stored resolution of min_y not compatible with y_offset and y_scale_factor: "); lidardouble2string(printstring, lasheader->min_y); fprintf(file_out, "%s\n", printstring);
      }
      if (!no_warnings && !valid_resolution(lasheader->min_z, lasheader->z_offset, lasheader->z_scale_factor))
      {
        fprintf(file_out, "WARNING: stored resolution of min_z not compatible with z_offset and z_scale_factor: "); lidardouble2string(printstring, lasheader->min_z); fprintf(file_out, "%s\n", printstring);
      }
      if (!no_warnings && !valid_resolution(lasheader->max_x, lasheader->x_offset, lasheader->x_scale_factor))
      {
        fprintf(file_out, "WARNING: stored resolution of max_x not compatible with x_offset and x_scale_factor: "); lidardouble2string(printstring, lasheader->max_x); fprintf(file_out, "%s\n", printstring);
      }
      if (!no_warnings && !valid_resolution(lasheader->max_y, lasheader->y_offset, lasheader->y_scale_factor))
      {
        fprintf(file_out, "WARNING: stored resolution of max_y not compatible with y_offset and y_scale_factor: "); lidardouble2string(printstring, lasheader->max_y); fprintf(file_out, "%s\n", printstring);
      }
      if (!no_warnings && !valid_resolution(lasheader->max_z, lasheader->z_offset, lasheader->z_scale_factor))
      {
        fprintf(file_out, "WARNING: stored resolution of max_z not compatible with z_offset and z_scale_factor: "); lidardouble2string(printstring, lasheader->max_z); fprintf(file_out, "%s\n", printstring);
      }
      if ((lasheader->version_major == 1) && (lasheader->version_minor >= 3))
      {
#ifdef _WIN32
        fprintf(file_out, "  start of waveform data packet record: %I64d\012", lasheader->start_of_waveform_data_packet_record);
#else
        fprintf(file_out, "  start of waveform data packet record: %lld\012", lasheader->start_of_waveform_data_packet_record);
#endif
      }
      if ((lasheader->version_major == 1) && (lasheader->version_minor >= 4))
      {
#ifdef _WIN32
        fprintf(file_out, "  start of first extended variable length record: %I64d\012", lasheader->start_of_first_extended_variable_length_record);
#else
        fprintf(file_out, "  start of first extended variable length record: %lld\012", lasheader->start_of_first_extended_variable_length_record);
#endif
        fprintf(file_out, "  number of extended_variable length records: %d\012", lasheader->number_of_extended_variable_length_records);
#ifdef _WIN32
        fprintf(file_out, "  extended number of point records: %I64d\012", lasheader->extended_number_of_point_records);
        fprintf(file_out, "  extended number of points by return: %I64d %I64d %I64d %I64d %I64d %I64d %I64d %I64d %I64d %I64d %I64d %I64d %I64d %I64d %I64d\012", lasheader->extended_number_of_points_by_return[0], lasheader->extended_number_of_points_by_return[1], lasheader->extended_number_of_points_by_return[2], lasheader->extended_number_of_points_by_return[3], lasheader->extended_number_of_points_by_return[4], lasheader->extended_number_of_points_by_return[5], lasheader->extended_number_of_points_by_return[6], lasheader->extended_number_of_points_by_return[7], lasheader->extended_number_of_points_by_return[8], lasheader->extended_number_of_points_by_return[9], lasheader->extended_number_of_points_by_return[10], lasheader->extended_number_of_points_by_return[11], lasheader->extended_number_of_points_by_return[12], lasheader->extended_number_of_points_by_return[13], lasheader->extended_number_of_points_by_return[14]);
#else
        fprintf(file_out, "  extended number of point records: %lld\012", lasheader->extended_number_of_point_records);
        fprintf(file_out, "  extended number of points by return: %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld\012", lasheader->extended_number_of_points_by_return[0], lasheader->extended_number_of_points_by_return[1], lasheader->extended_number_of_points_by_return[2], lasheader->extended_number_of_points_by_return[3], lasheader->extended_number_of_points_by_return[4], lasheader->extended_number_of_points_by_return[5], lasheader->extended_number_of_points_by_return[6], lasheader->extended_number_of_points_by_return[7], lasheader->extended_number_of_points_by_return[8], lasheader->extended_number_of_points_by_return[9], lasheader->extended_number_of_points_by_return[10], lasheader->extended_number_of_points_by_return[11], lasheader->extended_number_of_points_by_return[12], lasheader->extended_number_of_points_by_return[13], lasheader->extended_number_of_points_by_return[14]);
#endif
      }
      if (lasheader->user_data_in_header_size) fprintf(file_out, "the header contains %u user-defined bytes\012", lasheader->user_data_in_header_size);
    }

    if (file_out && !no_variable_header)
    {
      for (int i = 0; i < (int)lasheader->number_of_variable_length_records; i++)
      {
        fprintf(file_out, "variable length header record %d of %d:\012", i+1, (int)lasheader->number_of_variable_length_records);
        fprintf(file_out, "  reserved             %d\012", lasreader->header.vlrs[i].reserved);
          fprintf(file_out, "  user ID              '%s'\012", lasreader->header.vlrs[i].user_id);
        fprintf(file_out, "  record ID            %d\012", lasreader->header.vlrs[i].record_id);
        fprintf(file_out, "  length after header  %d\012", lasreader->header.vlrs[i].record_length_after_header);
          fprintf(file_out, "  description          '%s'\012", lasreader->header.vlrs[i].description);

        if ((strcmp(lasheader->vlrs[i].user_id, "LASF_Projection") == 0) && (lasheader->vlrs[i].data != 0))
        {
          if (lasheader->vlrs[i].record_id == 34735) 
          {
            fprintf(file_out, "    GeoKeyDirectoryTag version %d.%d.%d number of keys %d\012", lasheader->vlr_geo_keys->key_directory_version, lasheader->vlr_geo_keys->key_revision, lasheader->vlr_geo_keys->minor_revision, lasheader->vlr_geo_keys->number_of_keys);
            for (int j = 0; j < lasheader->vlr_geo_keys->number_of_keys; j++)
            {
              if (file_out)
              {
                fprintf(file_out, "      key %d tiff_tag_location %d count %d value_offset %d - ", lasheader->vlr_geo_key_entries[j].key_id, lasheader->vlr_geo_key_entries[j].tiff_tag_location, lasheader->vlr_geo_key_entries[j].count, lasheader->vlr_geo_key_entries[j].value_offset);
                switch (lasreader->header.vlr_geo_key_entries[j].key_id)
                {
                case 1024: 
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 1: 
                    fprintf(file_out, "GTModelTypeGeoKey: ModelTypeProjected\012");
                    break;
                  case 2:
                    fprintf(file_out, "GTModelTypeGeoKey: ModelTypeGeographic\012");
                    break;
                  case 3:
                    fprintf(file_out, "GTModelTypeGeoKey: ModelTypeGeocentric\012");
                    break;
                  case 0: 
                    fprintf(file_out, "GTModelTypeGeoKey: ModelTypeUndefined\012");
                    break;
                  default:
                    fprintf(file_out, "GTModelTypeGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                 }
                  break;
                case 1025: 
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 1: 
                    fprintf(file_out, "GTRasterTypeGeoKey: RasterPixelIsArea\012");
                    break;
                  case 2: 
                    fprintf(file_out, "GTRasterTypeGeoKey: RasterPixelIsPoint\012");
                    break;
                 default:
                    fprintf(file_out, "GTRasterTypeGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 1026: 
                  if (lasreader->header.vlr_geo_ascii_params)
                  {
                    char dummy[256];
                    strncpy(dummy, &(lasreader->header.vlr_geo_ascii_params[lasreader->header.vlr_geo_key_entries[j].value_offset]), lasreader->header.vlr_geo_key_entries[j].count);
                    dummy[lasreader->header.vlr_geo_key_entries[j].count-1] = '\0';
                    fprintf(file_out, "GTCitationGeoKey: %s\012",dummy);
                  }
                  break;
                case 2048: 
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 32767: 
                    fprintf(file_out, "GeographicTypeGeoKey: user-defined\012");
                    break;
                  case 4001: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Airy1830\012");
                    break;
                  case 4002: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_AiryModified1849\012");
                    break;
                  case 4003: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_AustralianNationalSpheroid\012");
                    break;
                  case 4004: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Bessel1841\012");
                    break;
                  case 4005: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Bessel1841Modified\012");
                    break;
                  case 4006: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_BesselNamibia\012");
                    break;
                  case 4008: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Clarke1866\012");
                    break;
                  case 4009: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Clarke1866Michigan\012");
                    break;
                  case 4010: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Clarke1880_Benoit\012");
                    break;
                  case 4011: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Clarke1880_IGN\012");
                    break;
                  case 4012: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Clarke1880_RGS\012");
                    break;
                  case 4013: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Clarke1880_Arc\012");
                    break;
                  case 4014: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Clarke1880_SGA1922\012");
                    break;
                  case 4015: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Everest1830_1937Adjustment\012");
                    break;
                  case 4016: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Everest1830_1967Definition\012");
                    break;
                  case 4017: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Everest1830_1975Definition\012");
                    break;
                  case 4018: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Everest1830Modified\012");
                    break;
                  case 4019: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_GRS1980\012");
                    break;
                  case 4020: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Helmert1906\012");
                    break;
                  case 4022: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_International1924\012");
                    break;
                  case 4023: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_International1967\012");
                    break;
                  case 4024: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Krassowsky1940\012");
                    break;
                  case 4030: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_WGS84\012");
                    break;
                  case 4034: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Clarke1880\012");
                    break;
                  case 4140: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_NAD83_CSRS\012");
                    break;
                  case 4167: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_New_Zealand_Geodetic_Datum_2000\012");
                    break;
                  case 4267: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCS_NAD27\012");
                    break;
                  case 4269: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCS_NAD83\012");
                    break;
                  case 4283: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCS_GDA94\012");
                    break;
                  case 4322: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCS_WGS_72\012");
                    break;
                  case 4326: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCS_WGS_84\012");
                    break;
                  case 4289: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCS_Amersfoort\012");
                    break;
                  case 4617: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCS_NAD83_CSRS\012");
                    break;
                  case 4619: 
                    fprintf(file_out, "GeographicTypeGeoKey: GCS_SWEREF99\012");
                    break;
                  default:
                    fprintf(file_out, "GeographicTypeGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 2049: 
                  if (lasreader->header.vlr_geo_ascii_params)
                  {
                    char dummy[256];
                    strncpy(dummy, &(lasreader->header.vlr_geo_ascii_params[lasreader->header.vlr_geo_key_entries[j].value_offset]), lasreader->header.vlr_geo_key_entries[j].count);
                    dummy[lasreader->header.vlr_geo_key_entries[j].count-1] = '\0';
                    fprintf(file_out, "GeogCitationGeoKey: %s\012",dummy);
                  }
                  break;
                case 2050: 
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 32767: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: user-defined\012");
                    break;
                  case 6202: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_Australian_Geodetic_Datum_1966\012");
                    break;
                  case 6203: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_Australian_Geodetic_Datum_1984\012");
                    break;
                  case 6267: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_North_American_Datum_1927\012");
                    break;
                  case 6269: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_North_American_Datum_1983\012");
                    break;
                  case 6283: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_Geocentric_Datum_of_Australia_1994\012");
                    break;
                  case 6322: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_WGS72\012");
                    break;
                  case 6326: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_WGS84\012");
                    break;
                  case 6140: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_NAD83_CSRS\012");
                    break;
                  case 6619: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_SWEREF99\012");
                    break;
                  case 6289: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_Amersfoort\012");
                    break;
                  case 6167: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_NZGD2000\012");
                    break;
                  case 6001: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Airy1830\012");
                    break;
                  case 6002: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_AiryModified1849\012");
                    break;
                  case 6003: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_AustralianNationalSpheroid\012");
                    break;
                  case 6004: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Bessel1841\012");
                    break;
                  case 6005: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_BesselModified\012");
                    break;
                  case 6006: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_BesselNamibia\012");
                    break;
                  case 6008: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Clarke1866\012");
                    break;
                  case 6009: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Clarke1866Michigan\012");
                    break;
                  case 6010: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Clarke1880_Benoit\012");
                    break;
                  case 6011: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Clarke1880_IGN\012");
                    break;
                  case 6012: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Clarke1880_RGS\012");
                    break;
                  case 6013: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Clarke1880_Arc\012");
                    break;
                  case 6014: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Clarke1880_SGA1922\012");
                    break;
                  case 6015: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Everest1830_1937Adjustment\012");
                    break;
                  case 6016: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Everest1830_1967Definition\012");
                    break;
                  case 6017: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Everest1830_1975Definition\012");
                    break;
                  case 6018: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Everest1830Modified\012");
                    break;
                  case 6019: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_GRS1980\012");
                    break;
                  case 6020: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Helmert1906\012");
                    break;
                  case 6022: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_International1924\012");
                    break;
                  case 6023: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_International1967\012");
                    break;
                  case 6024: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Krassowsky1940\012");
                    break;
                  case 6030: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_WGS84\012");
                    break;
                  case 6034: 
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Clarke1880\012");
                    break;
                  default:
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 2051: 
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 32767: 
                    fprintf(file_out, "GeogPrimeMeridianGeoKey: user-defined\012");
                    break;
                  case 8901: 
                    fprintf(file_out, "GeogPrimeMeridianGeoKey: PM_Greenwich\012");
                    break;
                  case 8902: 
                    fprintf(file_out, "GeogPrimeMeridianGeoKey: PM_Lisbon\012");
                    break;
                  default:
                    fprintf(file_out, "GeogPrimeMeridianGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 2052: 
                  horizontal_units = lasreader->header.vlr_geo_key_entries[j].value_offset;
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 9001: 
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Meter\012");
                    break;
                  case 9002: 
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Foot\012");
                    break;
                  case 9003: 
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Foot_US_Survey\012");
                    break;
                  case 9004: 
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Foot_Modified_American\012");
                    break;
                  case 9005: 
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Foot_Clarke\012");
                    break;
                  case 9006: 
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Foot_Indian\012");
                    break;
                  case 9007: 
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Link\012");
                    break;
                  case 9008: 
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Link_Benoit\012");
                    break;
                  case 9009: 
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Link_Sears\012");
                    break;
                  case 9010: 
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Chain_Benoit\012");
                    break;
                  case 9011: 
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Chain_Sears\012");
                    break;
                  case 9012: 
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Yard_Sears\012");
                    break;
                  case 9013: 
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Yard_Indian\012");
                    break;
                  case 9014: 
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Fathom\012");
                    break;
                  case 9015: 
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Mile_International_Nautical\012");
                    break;
                  default:
                    fprintf(file_out, "GeogLinearUnitsGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 2053: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "GeogLinearUnitSizeGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 2054: 
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 9101: 
                    fprintf(file_out, "GeogAngularUnitsGeoKey: Angular_Radian\012");
                    break;
                  case 9102: 
                    fprintf(file_out, "GeogAngularUnitsGeoKey: Angular_Degree\012");
                    break;
                  case 9103: 
                    fprintf(file_out, "GeogAngularUnitsGeoKey: Angular_Arc_Minute\012");
                    break;
                  case 9104: 
                    fprintf(file_out, "GeogAngularUnitsGeoKey: Angular_Arc_Second\012");
                    break;
                  case 9105: 
                    fprintf(file_out, "GeogAngularUnitsGeoKey: Angular_Grad\012");
                    break;
                  case 9106: 
                    fprintf(file_out, "GeogAngularUnitsGeoKey: Angular_Gon\012");
                    break;
                  case 9107: 
                    fprintf(file_out, "GeogAngularUnitsGeoKey: Angular_DMS\012");
                    break;
                  case 9108: 
                    fprintf(file_out, "GeogAngularUnitsGeoKey: Angular_DMS_Hemisphere\012");
                    break;
                  default:
                    fprintf(file_out, "GeogAngularUnitsGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 2055: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "GeogAngularUnitSizeGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 2056: 
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 32767: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: user-defined\012");
                    break;
                  case 7001: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Airy_1830\012");
                    break;
                  case 7002: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Airy_Modified_1849\012");
                    break;
                  case 7003: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Australian_National_Spheroid\012");
                    break;
                  case 7004: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Bessel_1841\012");
                    break;
                  case 7005: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Bessel_Modified\012");
                    break;
                  case 7006: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Bessel_Namibia\012");
                    break;
                  case 7008: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Clarke_1866\012");
                    break;
                  case 7009: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Clarke_1866_Michigan\012");
                    break;
                  case 7010: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Clarke1880_Benoit\012");
                    break;
                  case 7011: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Clarke1880_IGN\012");
                    break;
                  case 7012: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Clarke1880_RGS\012");
                    break;
                  case 7013: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Clarke1880_Arc\012");
                    break;
                  case 7014: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Clarke1880_SGA1922\012");
                    break;
                  case 7015: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Everest1830_1937Adjustment\012");
                    break;
                  case 7016: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Everest1830_1967Definition\012");
                    break;
                  case 7017: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Everest1830_1975Definition\012");
                    break;
                  case 7018: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Everest1830Modified\012");
                    break;
                  case 7019: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_GRS_1980\012");
                    break;
                  case 7020: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Helmert1906\012");
                    break;
                  case 7022: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_International1924\012");
                    break;
                  case 7023: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_International1967\012");
                    break;
                  case 7024: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Krassowsky1940\012");
                    break;
                  case 7030: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_WGS_84\012");
                    break;
                  case 7034: 
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Clarke_1880\012");
                    break;
                  default:
                    fprintf(file_out, "GeogEllipsoidGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 2057: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "GeogSemiMajorAxisGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 2058: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "GeogSemiMinorAxisGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 2059: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "GeogInvFlatteningGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 2060: 
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 9101: 
                    fprintf(file_out, "GeogAzimuthUnitsGeoKey: Angular_Radian\012");
                    break;
                  case 9102: 
                    fprintf(file_out, "GeogAzimuthUnitsGeoKey: Angular_Degree\012");
                    break;
                  case 9103: 
                    fprintf(file_out, "GeogAzimuthUnitsGeoKey: Angular_Arc_Minute\012");
                    break;
                  case 9104: 
                    fprintf(file_out, "GeogAzimuthUnitsGeoKey: Angular_Arc_Second\012");
                    break;
                  case 9105: 
                    fprintf(file_out, "GeogAzimuthUnitsGeoKey: Angular_Grad\012");
                    break;
                  case 9106: 
                    fprintf(file_out, "GeogAzimuthUnitsGeoKey: Angular_Gon\012");
                    break;
                  case 9107: 
                    fprintf(file_out, "GeogAzimuthUnitsGeoKey: Angular_DMS\012");
                    break;
                  case 9108: 
                    fprintf(file_out, "GeogAzimuthUnitsGeoKey: Angular_DMS_Hemisphere\012");
                    break;
                  default:
                    fprintf(file_out, "GeogAzimuthUnitsGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 2061: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "GeogPrimeMeridianLongGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 2062: 
                  switch (lasreader->header.vlr_geo_key_entries[j].count)
                  {
                  case 3:
                    if (lasreader->header.vlr_geo_double_params)
                    {
                      fprintf(file_out, "GeogTOWGS84GeoKey: TOWGS84[%.10g,%.10g,%.10g]\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset], lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset+1], lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset+2]);
                    }
                    else
                    {
                      fprintf(file_out, "GeogTOWGS84GeoKey: no vlr_geo_double_params. cannot look up the three parameters.\012");
                    }
                    break;
                  case 7:
                    if (lasreader->header.vlr_geo_double_params)
                    {
                      fprintf(file_out, "GeogTOWGS84GeoKey: TOWGS84[%.10g,%.10g,%.10g,%.10g,%.10g,%.10g,%.10g]\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset], lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset+1], lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset+2], lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset+3], lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset+4], lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset+5], lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset+6]);
                    }
                    else
                    {
                      fprintf(file_out, "GeogTOWGS84GeoKey: no vlr_geo_double_params. cannot look up the seven parameters.\012");
                    }
                    break;
                  default:
                    fprintf(file_out, "GeogTOWGS84GeoKey: look-up for type %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].count);
                  }
                  break;
                case 3072: 
                  if (geoprojectionconverter.set_ProjectedCSTypeGeoKey(lasreader->header.vlr_geo_key_entries[j].value_offset, printstring))
                  {
                    horizontal_units = geoprojectionconverter.get_ProjLinearUnitsGeoKey();
                    fprintf(file_out, "ProjectedCSTypeGeoKey: %s\012", printstring);
                    break;
                  }
                  else
                  {
                    fprintf(file_out, "ProjectedCSTypeGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 3073: 
                  if (lasreader->header.vlr_geo_ascii_params)
                  {
                    char dummy[256];
                    strncpy(dummy, &(lasreader->header.vlr_geo_ascii_params[lasreader->header.vlr_geo_key_entries[j].value_offset]), lasreader->header.vlr_geo_key_entries[j].count);
                    dummy[lasreader->header.vlr_geo_key_entries[j].count-1] = '\0';
                    fprintf(file_out, "PCSCitationGeoKey: %s\012",dummy);
                  }
                  break;
                case 3074: 
                  if ((16001 <= lasreader->header.vlr_geo_key_entries[j].value_offset) && (lasreader->header.vlr_geo_key_entries[j].value_offset <= 16060))
                  {
                    fprintf(file_out, "ProjectionGeoKey: Proj_UTM_zone_%dN\012", lasreader->header.vlr_geo_key_entries[j].value_offset - 16000);
                  }
                  else if ((16101 <= lasreader->header.vlr_geo_key_entries[j].value_offset) && (lasreader->header.vlr_geo_key_entries[j].value_offset <= 16160))
                  {
                    fprintf(file_out, "ProjectionGeoKey: Proj_UTM_zone_%dS\012", lasreader->header.vlr_geo_key_entries[j].value_offset - 16100);
                  }
                  else
                  {
                    switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                    {
                    case 32767: 
                      fprintf(file_out, "ProjectionGeoKey: user-defined\012");
                      break;
                    case 10101: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alabama_CS27_East\012");
                      break;
                    case 10102: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alabama_CS27_West\012");
                      break;
                    case 10131: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alabama_CS83_East\012");
                      break;
                    case 10132: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alabama_CS83_West\012");
                      break;
                    case 10201: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Arizona_Coordinate_System_east\012");
                      break;
                    case 10202: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Arizona_Coordinate_System_Central\012");
                      break;
                    case 10203: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Arizona_Coordinate_System_west\012");
                      break;
                    case 10231: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Arizona_CS83_east\012");
                      break;
                    case 10232: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Arizona_CS83_Central\012");
                      break;
                    case 10233: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Arizona_CS83_west\012");
                      break;
                    case 10301: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Arkansas_CS27_North\012");
                      break;
                    case 10302: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Arkansas_CS27_South\012");
                      break;
                    case 10331: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Arkansas_CS83_North\012");
                      break;
                    case 10332: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Arkansas_CS83_South\012");
                      break;
                    case 10401: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS27_I\012");
                      break;
                    case 10402: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS27_II\012");
                      break;
                    case 10403: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS27_III\012");
                      break;
                    case 10404: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS27_IV\012");
                      break;
                    case 10405: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS27_V\012");
                      break;
                    case 10406: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS27_VI\012");
                      break;
                    case 10407: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS27_VII\012");
                      break;
                    case 10431: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS83_1\012");
                      break;
                    case 10432: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS83_2\012");
                      break;
                    case 10433: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS83_3\012");
                      break;
                    case 10434: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS83_4\012");
                      break;
                    case 10435: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS83_5\012");
                      break;
                    case 10436: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS83_6\012");
                      break;
                    case 10501: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Colorado_CS27_North\012");
                      break;
                    case 10502: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Colorado_CS27_Central\012");
                      break;
                    case 10503: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Colorado_CS27_South\012");
                      break;
                    case 10531: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Colorado_CS83_North\012");
                      break;
                    case 10532: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Colorado_CS83_Central\012");
                      break;
                    case 10533: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Colorado_CS83_South\012");
                      break;
                    case 10600: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Connecticut_CS27\012");
                      break;
                    case 10630: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Connecticut_CS83\012");
                      break;
                    case 10700: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Delaware_CS27\012");
                      break;
                    case 10730: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Delaware_CS83\012");
                      break;
                    case 10901: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Florida_CS27_East\012");
                      break;
                    case 10902: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Florida_CS27_West\012");
                      break;
                    case 10903: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Florida_CS27_North\012");
                      break;
                    case 10931: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Florida_CS83_East\012");
                      break;
                    case 10932: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Florida_CS83_West\012");
                      break;
                    case 10933: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Florida_CS83_North\012");
                      break;
                    case 11001: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Georgia_CS27_East\012");
                      break;
                    case 11002: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Georgia_CS27_West\012");
                      break;
                    case 11031: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Georgia_CS83_East\012");
                      break;
                    case 11032: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Georgia_CS83_West\012");
                      break;
                    case 11101: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Idaho_CS27_East\012");
                      break;
                    case 11102: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Idaho_CS27_Central\012");
                      break;
                    case 11103: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Idaho_CS27_West\012");
                      break;
                    case 11131: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Idaho_CS83_East\012");
                      break;
                    case 11132: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Idaho_CS83_Central\012");
                      break;
                    case 11133: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Idaho_CS83_West\012");
                      break;
                    case 11201: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Illinois_CS27_East\012");
                      break;
                    case 11202: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Illinois_CS27_West\012");
                      break;
                    case 11231: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Illinois_CS83_East\012");
                      break;
                    case 11232: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Illinois_CS83_West\012");
                      break;
                    case 11301: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Indiana_CS27_East\012");
                      break;
                    case 11302: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Indiana_CS27_West\012");
                      break;
                    case 11331: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Indiana_CS83_East\012");
                      break;
                    case 11332: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Indiana_CS83_West\012");
                      break;
                    case 11401: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Iowa_CS27_North\012");
                      break;
                    case 11402: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Iowa_CS27_South\012");
                      break;
                    case 11431: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Iowa_CS83_North\012");
                      break;
                    case 11432: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Iowa_CS83_South\012");
                      break;
                    case 11501: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Kansas_CS27_North\012");
                      break;
                    case 11502: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Kansas_CS27_South\012");
                      break;
                    case 11531: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Kansas_CS83_North\012");
                      break;
                    case 11532: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Kansas_CS83_South\012");
                      break;
                    case 11601: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Kentucky_CS27_North\012");
                      break;
                    case 11602: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Kentucky_CS27_South\012");
                      break;
                    case 11631: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Kentucky_CS83_North\012");
                      break;
                    case 11632: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Kentucky_CS83_South\012");
                      break;
                    case 11701: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Louisiana_CS27_North\012");
                      break;
                    case 11702: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Louisiana_CS27_South\012");
                      break;
                    case 11731: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Louisiana_CS83_North\012");
                      break;
                    case 11732: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Louisiana_CS83_South\012");
                      break;
                    case 11801: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Maine_CS27_East\012");
                      break;
                    case 11802: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Maine_CS27_West\012");
                      break;
                    case 11831: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Maine_CS83_East\012");
                      break;
                    case 11832: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Maine_CS83_West\012");
                      break;
                    case 11900: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Maryland_CS27\012");
                      break;
                    case 11930: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Maryland_CS83\012");
                      break;
                    case 12001: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Massachusetts_CS27_Mainland\012");
                      break;
                    case 12002: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Massachusetts_CS27_Island\012");
                      break;
                    case 12031: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Massachusetts_CS83_Mainland\012");
                      break;
                    case 12032: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Massachusetts_CS83_Island\012");
                      break;
                    case 12101: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Michigan_State_Plane_East\012");
                      break;
                    case 12102: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Michigan_State_Plane_Old_Central\012");
                      break;
                    case 12103: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Michigan_State_Plane_West\012");
                      break;
                    case 12111: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Michigan_CS27_North\012");
                      break;
                    case 12112: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Michigan_CS27_Central\012");
                      break;
                    case 12113: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Michigan_CS27_South\012");
                      break;
                    case 12141: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Michigan_CS83_North\012");
                      break;
                    case 12142: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Michigan_CS83_Central\012");
                      break;
                    case 12143: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Michigan_CS83_South\012");
                      break;
                    case 12201: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Minnesota_CS27_North\012");
                      break;
                    case 12202: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Minnesota_CS27_Central\012");
                      break;
                    case 12203: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Minnesota_CS27_South\012");
                      break;
                    case 12231: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Minnesota_CS83_North\012");
                      break;
                    case 12232: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Minnesota_CS83_Central\012");
                      break;
                    case 12233: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Minnesota_CS83_South\012");
                      break;
                    case 12301: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Mississippi_CS27_East\012");
                      break;
                    case 12302: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Mississippi_CS27_West\012");
                      break;
                    case 12331: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Mississippi_CS83_East\012");
                      break;
                    case 12332: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Mississippi_CS83_West\012");
                      break;
                    case 12401: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Missouri_CS27_East\012");
                      break;
                    case 12402: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Missouri_CS27_Central\012");
                      break;
                    case 12403: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Missouri_CS27_West\012");
                      break;
                    case 12431: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Missouri_CS83_East\012");
                      break;
                    case 12432: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Missouri_CS83_Central\012");
                      break;
                    case 12433: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Missouri_CS83_West\012");
                      break;
                    case 12501: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Montana_CS27_North\012");
                      break;
                    case 12502: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Montana_CS27_Central\012");
                      break;
                    case 12503: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Montana_CS27_South\012");
                      break;
                    case 12530: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Montana_CS83\012");
                      break;
                    case 12601: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Nebraska_CS27_North\012");
                      break;
                    case 12602: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Nebraska_CS27_South\012");
                      break;
                    case 12630: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Nebraska_CS83\012");
                      break;
                    case 12701: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Nevada_CS27_East\012");
                      break;
                    case 12702: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Nevada_CS27_Central\012");
                      break;
                    case 12703: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Nevada_CS27_West\012");
                      break;
                    case 12731: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Nevada_CS83_East\012");
                      break;
                    case 12732: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Nevada_CS83_Central\012");
                      break;
                    case 12733: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Nevada_CS83_West\012");
                      break;
                    case 12800: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Hampshire_CS27\012");
                      break;
                    case 12830: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Hampshire_CS83\012");
                      break;
                    case 12900: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Jersey_CS27\012");
                      break;
                    case 12930: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Jersey_CS83\012");
                      break;
                    case 13001: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Mexico_CS27_East\012");
                      break;
                    case 13002: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Mexico_CS27_Central\012");
                      break;
                    case 13003: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Mexico_CS27_West\012");
                      break;
                    case 13031: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Mexico_CS83_East\012");
                      break;
                    case 13032: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Mexico_CS83_Central\012");
                      break;
                    case 13033: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Mexico_CS83_West\012");
                      break;
                    case 13101: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_York_CS27_East\012");
                      break;
                    case 13102: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_York_CS27_Central\012");
                      break;
                    case 13103: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_York_CS27_West\012");
                      break;
                    case 13104: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_York_CS27_Long_Island\012");
                      break;
                    case 13131: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_York_CS83_East\012");
                      break;
                    case 13132: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_York_CS83_Central\012");
                      break;
                    case 13133: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_York_CS83_West\012");
                      break;
                    case 13134: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_York_CS83_Long_Island\012");
                      break;
                    case 13200: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_North_Carolina_CS27\012");
                      break;
                    case 13230: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_North_Carolina_CS83\012");
                      break;
                    case 13301: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_North_Dakota_CS27_North\012");
                      break;
                    case 13302: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_North_Dakota_CS27_South\012");
                      break;
                    case 13331: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_North_Dakota_CS83_North\012");
                      break;
                    case 13332: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_North_Dakota_CS83_South\012");
                      break;
                    case 13401: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Ohio_CS27_North\012");
                      break;
                    case 13402: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Ohio_CS27_South\012");
                      break;
                    case 13431: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Ohio_CS83_North\012");
                      break;
                    case 13432: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Ohio_CS83_South\012");
                      break;
                    case 13501: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Oklahoma_CS27_North\012");
                      break;
                    case 13502: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Oklahoma_CS27_South\012");
                      break;
                    case 13531: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Oklahoma_CS83_North\012");
                      break;
                    case 13532: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Oklahoma_CS83_South\012");
                      break;
                    case 13601: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Oregon_CS27_North\012");
                      break;
                    case 13602: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Oregon_CS27_South\012");
                      break;
                    case 13631: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Oregon_CS83_North\012");
                      break;
                    case 13632: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Oregon_CS83_South\012");
                      break;
                    case 13701: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Pennsylvania_CS27_North\012");
                      break;
                    case 13702: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Pennsylvania_CS27_South\012");
                      break;
                    case 13731: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Pennsylvania_CS83_North\012");
                      break;
                    case 13732: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Pennsylvania_CS83_South\012");
                      break;
                    case 13800: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Rhode_Island_CS27\012");
                      break;
                    case 13830: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Rhode_Island_CS83\012");
                      break;
                    case 13901: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_South_Carolina_CS27_North\012");
                      break;
                    case 13902: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_South_Carolina_CS27_South\012");
                      break;
                    case 13930: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_South_Carolina_CS83\012");
                      break;
                    case 14001: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_South_Dakota_CS27_North\012");
                      break;
                    case 14002: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_South_Dakota_CS27_South\012");
                      break;
                    case 14031: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_South_Dakota_CS83_North\012");
                      break;
                    case 14032: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_South_Dakota_CS83_South\012");
                      break;
                    case 14100: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Tennessee_CS27\012");
                      break;
                    case 14130: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Tennessee_CS83\012");
                      break;
                    case 14201: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Texas_CS27_North\012");
                      break;
                    case 14202: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Texas_CS27_North_Central\012");
                      break;
                    case 14203: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Texas_CS27_Central\012");
                      break;
                    case 14204: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Texas_CS27_South_Central\012");
                      break;
                    case 14205: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Texas_CS27_South\012");
                      break;
                    case 14231: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Texas_CS83_North\012");
                      break;
                    case 14232: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Texas_CS83_North_Central\012");
                      break;
                    case 14233: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Texas_CS83_Central\012");
                      break;
                    case 14234: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Texas_CS83_South_Central\012");
                      break;
                    case 14235: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Texas_CS83_South\012");
                      break;
                    case 14301: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Utah_CS27_North\012");
                      break;
                    case 14302: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Utah_CS27_Central\012");
                      break;
                    case 14303: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Utah_CS27_South\012");
                      break;
                    case 14331: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Utah_CS83_North\012");
                      break;
                    case 14332: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Utah_CS83_Central\012");
                      break;
                    case 14333: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Utah_CS83_South\012");
                      break;
                    case 14400: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Vermont_CS27\012");
                      break;
                    case 14430: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Vermont_CS83\012");
                      break;
                    case 14501: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Virginia_CS27_North\012");
                      break;
                    case 14502: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Virginia_CS27_South\012");
                      break;
                    case 14531: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Virginia_CS83_North\012");
                      break;
                    case 14532: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Virginia_CS83_South\012");
                      break;
                    case 14601: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Washington_CS27_North\012");
                      break;
                    case 14602: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Washington_CS27_South\012");
                      break;
                    case 14631: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Washington_CS83_North\012");
                      break;
                    case 14632: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Washington_CS83_South\012");
                      break;
                    case 14701: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_West_Virginia_CS27_North\012");
                      break;
                    case 14702: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_West_Virginia_CS27_South\012");
                      break;
                    case 14731: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_West_Virginia_CS83_North\012");
                      break;
                    case 14732: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_West_Virginia_CS83_South\012");
                      break;
                    case 14801: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wisconsin_CS27_North\012");
                      break;
                    case 14802: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wisconsin_CS27_Central\012");
                      break;
                    case 14803: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wisconsin_CS27_South\012");
                      break;
                    case 14831: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wisconsin_CS83_North\012");
                      break;
                    case 14832: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wisconsin_CS83_Central\012");
                      break;
                    case 14833: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wisconsin_CS83_South\012");
                      break;
                    case 14901: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wyoming_CS27_East\012");
                      break;
                    case 14902: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wyoming_CS27_East_Central\012");
                      break;
                    case 14903: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wyoming_CS27_West_Central\012");
                      break;
                    case 14904: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wyoming_CS27_West\012");
                      break;
                    case 14931: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wyoming_CS83_East\012");
                      break;
                    case 14932: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wyoming_CS83_East_Central\012");
                      break;
                    case 14933: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wyoming_CS83_West_Central\012");
                      break;
                    case 14934: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wyoming_CS83_West\012");
                      break;
                    case 15001: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS27_1\012");
                      break;
                    case 15002: 
                      fprintf(file_out, "ProjectionGeoKey: ProjectionGeoKey\012");
                      break;
                    case 15003: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS27_3\012");
                      break;
                    case 15004: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS27_4\012");
                      break;
                    case 15005: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS27_5\012");
                      break;
                    case 15006: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS27_6\012");
                      break;
                    case 15007: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS27_7\012");
                      break;
                    case 15008: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS27_8\012");
                      break;
                    case 15009: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS27_9\012");
                      break;
                    case 15010: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS27_10\012");
                      break;
                    case 15031: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS83_1\012");
                      break;
                    case 15032: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS83_2\012");
                      break;
                    case 15033: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS83_3\012");
                      break;
                    case 15034: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS83_4\012");
                      break;
                    case 15035: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS83_5\012");
                      break;
                    case 15036: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS83_6\012");
                      break;
                    case 15037: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS83_7\012");
                      break;
                    case 15038: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS83_8\012");
                      break;
                    case 15039: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS83_9\012");
                      break;
                    case 15040: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS83_10\012");
                      break;
                    case 15101: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Hawaii_CS27_1\012");
                      break;
                    case 15102: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Hawaii_CS27_2\012");
                      break;
                    case 15103: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Hawaii_CS27_3\012");
                      break;
                    case 15104: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Hawaii_CS27_4\012");
                      break;
                    case 15105: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Hawaii_CS27_5\012");
                      break;
                    case 15131: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Hawaii_CS83_1\012");
                      break;
                    case 15132: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Hawaii_CS83_2\012");
                      break;
                    case 15133: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Hawaii_CS83_3\012");
                      break;
                    case 15134: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Hawaii_CS83_4\012");
                      break;
                    case 15135: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Hawaii_CS83_5\012");
                      break;
                    case 15201: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Puerto_Rico_CS27\012");
                      break;
                    case 15202: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_St_Croix\012");
                      break;
                    case 15230: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Puerto_Rico_Virgin_Is\012");
                      break;
                    case 15914: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_BLM_14N_feet\012");
                      break;
                    case 15915: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_BLM_15N_feet\012");
                      break;
                    case 15916: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_BLM_16N_feet\012");
                      break;
                    case 15917: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_BLM_17N_feet\012");
                      break;
                    case 17333: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_SWEREF99_TM\012");
                      break;
                    case 17348: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_48\012");
                      break;
                    case 17349: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_49\012");
                      break;
                    case 17350: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_50\012");
                      break;
                    case 17351: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_51\012");
                      break;
                    case 17352: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_52\012");
                      break;
                    case 17353: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_53\012");
                      break;
                    case 17354: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_54\012");
                      break;
                    case 17355: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_55\012");
                      break;
                    case 17356: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_56\012");
                      break;
                    case 17357: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_57\012");
                      break;
                    case 17358: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_58\012");
                      break;
                    case 17448: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_48\012");
                      break;
                    case 17449: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_49\012");
                      break;
                    case 17450: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_50\012");
                      break;
                    case 17451: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_51\012");
                      break;
                    case 17452: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_52\012");
                      break;
                    case 17453: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_53\012");
                      break;
                    case 17454: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_54\012");
                      break;
                    case 17455: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_55\012");
                      break;
                    case 17456: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_56\012");
                      break;
                    case 17457: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_57\012");
                      break;
                    case 17458: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_58\012");
                      break;
                    case 18031: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Argentina_1\012");
                      break;
                    case 18032: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Argentina_2\012");
                      break;
                    case 18033: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Argentina_3\012");
                      break;
                    case 18034: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Argentina_4\012");
                      break;
                    case 18035: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Argentina_5\012");
                      break;
                    case 18036: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Argentina_6\012");
                      break;
                    case 18037: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Argentina_7\012");
                      break;
                    case 18051: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Colombia_3W\012");
                      break;
                    case 18052: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Colombia_Bogota\012");
                      break;
                    case 18053: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Colombia_3E\012");
                      break;
                    case 18054: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Colombia_6E\012");
                      break;
                    case 18072: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Egypt_Red_Belt\012");
                      break;
                    case 18073: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Egypt_Purple_Belt\012");
                      break;
                    case 18074: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Extended_Purple_Belt\012");
                      break;
                    case 18141: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Zealand_North_Island_Nat_Grid\012");
                      break;
                    case 18142: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Zealand_South_Island_Nat_Grid\012");
                      break;
                    case 19900: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Bahrain_Grid\012");
                      break;
                    case 19905: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_Netherlands_E_Indies_Equatorial\012");
                      break;
                    case 19912: 
                      fprintf(file_out, "ProjectionGeoKey: Proj_RSO_Borneo\012");
                      break;
                    default:
                      fprintf(file_out, "ProjectionGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  }
                  break;
                case 3075: 
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 1: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_TransverseMercator\012");
                    break;
                  case 2: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_TransvMercator_Modified_Alaska\012");
                    break;
                  case 3: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_ObliqueMercator\012");
                    break;
                  case 4: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_ObliqueMercator_Laborde\012");
                    break;
                  case 5: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_ObliqueMercator_Rosenmund\012");
                    break;
                  case 6: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_ObliqueMercator_Spherical\012");
                    break;
                  case 7: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_Mercator\012");
                    break;
                  case 8: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_LambertConfConic_2SP\012");
                    break;
                  case 9: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_LambertConfConic_Helmert\012");
                    break;
                  case 10: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_LambertAzimEqualArea\012");
                    break;
                  case 11: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_AlbersEqualArea\012");
                    break;
                  case 12: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_AzimuthalEquidistant\012");
                    break;
                  case 13: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_EquidistantConic\012");
                    break;
                  case 14: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_Stereographic\012");
                    break;
                  case 15: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_PolarStereographic\012");
                    break;
                  case 16: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_ObliqueStereographic\012");
                    break;
                  case 17: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_Equirectangular\012");
                    break;
                  case 18: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_CassiniSoldner\012");
                    break;
                  case 19: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_Gnomonic\012");
                    break;
                  case 20: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_MillerCylindrical\012");
                    break;
                  case 21: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_Orthographic\012");
                    break;
                  case 22: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_Polyconic\012");
                    break;
                  case 23: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_Robinson\012");
                    break;
                  case 24: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_Sinusoidal\012");
                    break;
                  case 25: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_VanDerGrinten\012");
                    break;
                  case 26: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_NewZealandMapGrid\012");
                    break;
                  case 27: 
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_TransvMercator_SouthOriented\012");
                    break;
                  default:
                    fprintf(file_out, "ProjCoordTransGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 3076: 
                  horizontal_units = lasreader->header.vlr_geo_key_entries[j].value_offset;
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 9001: 
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Meter\012");
                    break;
                  case 9002: 
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Foot\012");
                    break;
                  case 9003: 
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Foot_US_Survey\012");
                    break;
                  case 9004: 
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Foot_Modified_American\012");
                    break;
                  case 9005: 
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Foot_Clarke\012");
                    break;
                  case 9006: 
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Foot_Indian\012");
                    break;
                  case 9007: 
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Link\012");
                    break;
                  case 9008: 
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Link_Benoit\012");
                    break;
                  case 9009: 
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Link_Sears\012");
                    break;
                  case 9010: 
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Chain_Benoit\012");
                    break;
                  case 9011: 
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Chain_Sears\012");
                    break;
                  case 9012: 
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Yard_Sears\012");
                    break;
                  case 9013: 
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Yard_Indian\012");
                    break;
                  case 9014: 
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Fathom\012");
                    break;
                  case 9015: 
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Mile_International_Nautical\012");
                    break;
                  default:
                    fprintf(file_out, "ProjLinearUnitsGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 3077: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjLinearUnitSizeGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3078: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjStdParallel1GeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3079: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjStdParallel2GeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;        
                case 3080: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjNatOriginLongGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3081: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjNatOriginLatGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3082: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjFalseEastingGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3083: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjFalseNorthingGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3084: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjFalseOriginLongGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3085: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjFalseOriginLatGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3086: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjFalseOriginEastingGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3087: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjFalseOriginNorthingGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3088: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjCenterLongGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3089: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjCenterLatGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3090: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjCenterEastingGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3091: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjCenterNorthingGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3092: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjScaleAtNatOriginGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3093: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjScaleAtCenterGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3094: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjAzimuthAngleGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3095: 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjStraightVertPoleLongGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 4096: 
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 1127: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Canadian_Geodetic_Vertical_Datum_2013\012");
                    break;
                  case 5001: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Airy_1830_ellipsoid\012");
                    break;
                  case 5002: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Airy_Modified_1849_ellipsoid\012");
                    break;
                  case 5003: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_ANS_ellipsoid\012");
                    break;
                  case 5004: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Bessel_1841_ellipsoid\012");
                    break;
                  case 5005: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Bessel_Modified_ellipsoid\012");
                    break;
                  case 5006: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Bessel_Namibia_ellipsoid\012");
                    break;
                  case 5007: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Clarke_1858_ellipsoid\012");
                    break;
                  case 5008: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Clarke_1866_ellipsoid\012");
                    break;
                  case 5010: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Clarke_1880_Benoit_ellipsoid\012");
                    break;
                  case 5011: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Clarke_1880_IGN_ellipsoid\012");
                    break;
                  case 5012: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Clarke_1880_RGS_ellipsoid\012");
                    break;
                  case 5013: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Clarke_1880_Arc_ellipsoid\012");
                    break;
                  case 5014: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Clarke_1880_SGA_1922_ellipsoid\012");
                    break;
                  case 5015: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Everest_1830_1937_Adjustment_ellipsoid\012");
                    break;
                  case 5016: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Everest_1830_1967_Definition_ellipsoid\012");
                    break;
                  case 5017: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Everest_1830_1975_Definition_ellipsoid\012");
                    break;
                  case 5018: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Everest_1830_Modified_ellipsoid\012");
                    break;
                  case 5019: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_GRS_1980_ellipsoid\012");
                    break;
                  case 5020: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Helmert_1906_ellipsoid\012");
                    break;
                  case 5021: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_INS_ellipsoid\012");
                    break;
                  case 5022: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_International_1924_ellipsoid\012");
                    break;
                  case 5023: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_International_1967_ellipsoid\012");
                    break;
                  case 5024: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Krassowsky_1940_ellipsoid\012");
                    break;
                  case 5025: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_NWL_9D_ellipsoid\012");
                    break;
                  case 5026: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_NWL_10D_ellipsoid\012");
                    break;
                  case 5027: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Plessis_1817_ellipsoid\012");
                    break;
                  case 5028: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Struve_1860_ellipsoid\012");
                    break;
                  case 5029: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_War_Office_ellipsoid\012");
                    break;
                  case 5030: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_WGS_84_ellipsoid\012");
                    break;
                  case 5031: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_GEM_10C_ellipsoid\012");
                    break;
                  case 5032: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_OSU86F_ellipsoid\012");
                    break;
                  case 5033: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_OSU91A_ellipsoid\012");
                    break;
                  case 5101: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Newlyn\012");
                    break;
                  case 5102: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_North_American_Vertical_Datum_1929\012");
                    break;
                  case 5103: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_North_American_Vertical_Datum_1988\012");
                    break;
                  case 5104: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Yellow_Sea_1956\012");
                    break;
                  case 5105: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Baltic_Sea\012");
                    break;
                  case 5106: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Caspian_Sea\012");
                    break;
                  case 5114: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Canadian_Geodetic_Vertical_Datum_1928\012");
                    break;
                  case 5206: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Dansk_Vertikal_Reference_1990\012");
                    break;
                  case 5215: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_European_Vertical_Reference_Frame_2007\012");
                    break;
                  case 5701: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: ODN height (Reserved EPSG)\012");
                    break;
                  case 5702: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: NGVD29 height (Reserved EPSG)\012");
                    break;
                  case 5703: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: NAVD88 height (Reserved EPSG)\012");
                    break;
                  case 5704: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: Yellow Sea (Reserved EPSG)\012");
                    break;
                  case 5705: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: Baltic height (Reserved EPSG)\012");
                    break;
                  case 5706: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: Caspian depth (Reserved EPSG)\012");
                    break;
                  case 5707: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: NAP height (Reserved EPSG)\012");
                    break;
                  case 5710: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: Oostende height (Reserved EPSG)\012");
                    break;
                  case 5711: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: AHD height (Reserved EPSG)\012");
                    break;
                  case 5712: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: AHD (Tasmania) height (Reserved EPSG)\012");
                    break;
                  case 5776: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: Norway Normal Null 1954\012");
                    break;
                  case 5783: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: Deutsches Haupthoehennetz 1992\012");
                    break;
                  case 5941: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: Norway Normal Null 2000\012");
                    break;
                  case 6647: 
                    fprintf(file_out, "VerticalCSTypeGeoKey: Canadian Geodetic Vertical Datum of 2013\012");
                    break;
                  default:
                    fprintf(file_out, "VerticalCSTypeGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 4097: 
                  if (lasreader->header.vlr_geo_ascii_params)
                  {
                    char dummy[256];
                    strncpy(dummy, &(lasreader->header.vlr_geo_ascii_params[lasreader->header.vlr_geo_key_entries[j].value_offset]), lasreader->header.vlr_geo_key_entries[j].count);
                    dummy[lasreader->header.vlr_geo_key_entries[j].count-1] = '\0';
                    fprintf(file_out, "VerticalCitationGeoKey: %s\012",dummy);
                  }
                  break;
                case 4098: 
                  fprintf(file_out, "VerticalDatumGeoKey: Vertical Datum Codes %d\012",lasreader->header.vlr_geo_key_entries[j].value_offset);
                  break;
                case 4099: 
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 9001: 
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Meter\012");
                    break;
                  case 9002: 
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Foot\012");
                    break;
                  case 9003: 
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Foot_US_Survey\012");
                    break;
                  case 9004: 
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Foot_Modified_American\012");
                    break;
                  case 9005: 
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Foot_Clarke\012");
                    break;
                  case 9006: 
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Foot_Indian\012");
                    break;
                  case 9007: 
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Link\012");
                    break;
                  case 9008: 
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Link_Benoit\012");
                    break;
                  case 9009: 
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Link_Sears\012");
                    break;
                  case 9010: 
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Chain_Benoit\012");
                    break;
                  case 9011: 
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Chain_Sears\012");
                    break;
                  case 9012: 
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Yard_Sears\012");
                    break;
                  case 9013: 
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Yard_Indian\012");
                    break;
                  case 9014: 
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Fathom\012");
                    break;
                  case 9015: 
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Mile_International_Nautical\012");
                    break;
                  default:
                    fprintf(file_out, "VerticalUnitsGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                default:
                  fprintf(file_out, "key ID %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].key_id);
                }
              }
            }
          }
          else if (lasheader->vlrs[i].record_id == 34736) 
          {
            fprintf(file_out, "    GeoDoubleParamsTag (number of doubles %d)\012", lasreader->header.vlrs[i].record_length_after_header/8);
            fprintf(file_out, "      ");
            for (int j = 0; j < lasreader->header.vlrs[i].record_length_after_header/8; j++)
            {
              fprintf(file_out, "%lg ", lasheader->vlr_geo_double_params[j]);
            }
            fprintf(file_out, "\012");
          }
          else if (lasheader->vlrs[i].record_id == 34737) 
          {
            fprintf(file_out, "    GeoAsciiParamsTag (number of characters %d)\012", lasreader->header.vlrs[i].record_length_after_header);
            fprintf(file_out, "      ");
            for (int j = 0; j < lasreader->header.vlrs[i].record_length_after_header; j++)
            {
              if (lasheader->vlr_geo_ascii_params[j] >= ' ')
              {
                fprintf(file_out, "%c", lasheader->vlr_geo_ascii_params[j]);
              }
              else
              {
                fprintf(file_out, " ");
              }
            }
            fprintf(file_out, "\012");
          }
          else if (lasheader->vlrs[i].record_id == 2111) 
          {
            fprintf(file_out, "    WKT OGC MATH TRANSFORM:\012");
            fprintf(file_out, "    %s\012", lasreader->header.vlrs[i].data);
          }
          else if (lasheader->vlrs[i].record_id == 2112) 
          {
            fprintf(file_out, "    WKT OGC COORDINATE SYSTEM:\012");
            fprintf(file_out, "    %s\012", lasreader->header.vlrs[i].data);
          }
        }
        else if ((strcmp(lasheader->vlrs[i].user_id, "LASF_Spec") == 0) && (lasheader->vlrs[i].data != 0))
        {
          if (lasheader->vlrs[i].record_id == 0) 
          {
            LASvlr_classification* vlr_classification = (LASvlr_classification*)lasheader->vlrs[i].data;
            int num = lasheader->vlrs[i].record_length_after_header / sizeof(LASvlr_classification);
            for (int j = 0; j < num; j++)
            {
              fprintf(file_out, "    %d %.15s", vlr_classification[j].class_number, vlr_classification[j].description);
            }
            if (num) fprintf(file_out, "\012");
          }
          else if (lasheader->vlrs[i].record_id == 2) 
          {
          }
          else if (lasheader->vlrs[i].record_id == 3) 
          {
            fprintf(file_out, "    ");
            for (int j = 0; j < lasheader->vlrs[i].record_length_after_header; j++)
            {
              if (lasheader->vlrs[i].data[j] != '\0')
              {
                fprintf(file_out, "%c", lasheader->vlrs[i].data[j]);
              }
              else
              {
                fprintf(file_out, " ");
              }
            }
            fprintf(file_out, "\012");
          }
          else if (lasheader->vlrs[i].record_id == 4) 
          {
            const char* name_table[10] = { "unsigned char", "char", "unsigned short", "short", "unsigned long", "long", "unsigned long long", "long long", "float", "double" };
            fprintf(file_out, "    Extra Byte Descriptions\012");
            for (int j = 0; j < lasheader->vlrs[i].record_length_after_header; j += 192)
            {
              if (lasheader->vlrs[i].data[j+2])
              {
                int type = ((I32)(lasheader->vlrs[i].data[j+2])-1)%10;
                int dim = ((I32)(lasheader->vlrs[i].data[j+2])-1)/10+1;
                if (file_out)
                {
                  fprintf(file_out, "      data type: %d (%s), name \"%s\", description: \"%s\"", (I32)(lasheader->vlrs[i].data[j+2]), name_table[type], (char*)(lasheader->vlrs[i].data + j + 4), (char*)(lasheader->vlrs[i].data + j + 160));
                  if (lasheader->vlrs[i].data[j+3] & 0x02) 
                  {
                    fprintf(file_out, ", min:");
                    for (int k = 0; k < dim; k++)
                    {
                      if (type < 8)
                      {
#ifdef _WIN32
                        fprintf(file_out, " %I64d", ((I64*)(lasheader->vlrs[i].data + j + 64))[k]);
#else
                        fprintf(file_out, ", %lld", ((I64*)(lasheader->vlrs[i].data + j + 64))[k]);
#endif
                      }
                      else
                      {
                        fprintf(file_out, " %g", ((F64*)(lasheader->vlrs[i].data + j + 64))[k]);
                      }
                    }
                  }
                  if (lasheader->vlrs[i].data[j+3] & 0x04) 
                  {
                    fprintf(file_out, ", max:");
                    for (int k = 0; k < dim; k++)
                    {
                      if (type < 8)
                      {
#ifdef _WIN32
                        fprintf(file_out, " %I64d", ((I64*)(lasheader->vlrs[i].data + j + 88))[k]);
#else
                        fprintf(file_out, ", %lld", ((I64*)(lasheader->vlrs[i].data + j + 88))[k]);
#endif
                      }
                      else
                      {
                        fprintf(file_out, " %g", ((F64*)(lasheader->vlrs[i].data + j + 88))[k]);
                      }
                    }
                  }
                  if (lasheader->vlrs[i].data[j+3] & 0x08) 
                  {
                    fprintf(file_out, ", scale:");
                    for (int k = 0; k < dim; k++)
                    {
                      fprintf(file_out, " %g", ((F64*)(lasheader->vlrs[i].data + j + 112))[k]);
                    }
                  }
                  else
                  {
                    fprintf(file_out, ", scale: 1 (not set)");
                  }
                  if (lasheader->vlrs[i].data[j+3] & 0x10) 
                  {
                    fprintf(file_out, ", offset:");
                    for (int k = 0; k < dim; k++)
                    {
                      fprintf(file_out, " %g", ((F64*)(lasheader->vlrs[i].data + j + 136))[k]);
                    }
                  }
                  else
                  {
                    fprintf(file_out, ", offset: 0 (not set)");
                  }
                  fprintf(file_out, "\012");
                }
              }
              else
              {
                fprintf(file_out, "      data type: 0 (untyped bytes), size: %d\012", lasheader->vlrs[i].data[j+3]);
              }
            }
          }
          else if ((lasheader->vlrs[i].record_id >= 100) && (lasheader->vlrs[i].record_id < 355)) 
          {
            LASvlr_wave_packet_descr* vlr_wave_packet_descr = (LASvlr_wave_packet_descr*)lasheader->vlrs[i].data;
            fprintf(file_out, "  index %d bits/sample %d compression %d samples %u temporal %u gain %lg, offset %lg\012", lasheader->vlrs[i].record_id-99, vlr_wave_packet_descr->getBitsPerSample(), vlr_wave_packet_descr->getCompressionType(), vlr_wave_packet_descr->getNumberOfSamples(), vlr_wave_packet_descr->getTemporalSpacing(), vlr_wave_packet_descr->getDigitizerGain(), vlr_wave_packet_descr->getDigitizerOffset());
          }
        }
      }
    }

    if (file_out && !no_variable_header)
    {
      for (int i = 0; i < (int)lasheader->number_of_extended_variable_length_records; i++)
      {
        fprintf(file_out, "extended variable length header record %d of %d:\012", i+1, (int)lasheader->number_of_extended_variable_length_records);
        fprintf(file_out, "  reserved             %d\012", lasreader->header.evlrs[i].reserved);
          fprintf(file_out, "  user ID              '%s'\012", lasreader->header.evlrs[i].user_id);
        fprintf(file_out, "  record ID            %d\012", lasreader->header.evlrs[i].record_id);
#ifdef _WIN32
        fprintf(file_out, "  length after header  %I64d\012", lasreader->header.evlrs[i].record_length_after_header);
#else
        fprintf(file_out, "  length after header  %lld\012", lasreader->header.evlrs[i].record_length_after_header);
#endif
          fprintf(file_out, "  description          '%s'\012", lasreader->header.evlrs[i].description);
        if (strcmp(lasheader->evlrs[i].user_id, "LASF_Projection") == 0)
        {
          if (lasheader->evlrs[i].record_id == 2111) 
          {
            fprintf(file_out, "    OGC MATH TRANSFORM WKT:\012");
            fprintf(file_out, "    %s\012", lasreader->header.evlrs[i].data);
          }
          else if (lasheader->evlrs[i].record_id == 2112) 
          {
            fprintf(file_out, "    OGC COORDINATE SYSTEM WKT:\012");
            fprintf(file_out, "    %s\012", lasreader->header.evlrs[i].data);
          }
        }
      }
    }

    if (file_out && !no_header)
    {
      if (lasheader->user_data_after_header_size) fprintf(file_out, "the header is followed by %u user-defined bytes\012", lasheader->user_data_after_header_size);

      if (lasheader->laszip)
      {
        fprintf(file_out, "LASzip compression (version %d.%dr%d c%d", lasheader->laszip->version_major, lasheader->laszip->version_minor, lasheader->laszip->version_revision, lasheader->laszip->compressor);
        if ((lasheader->laszip->compressor == LASZIP_COMPRESSOR_CHUNKED) || (lasheader->laszip->compressor == LASZIP_COMPRESSOR_LAYERED_CHUNKED)) fprintf(file_out, " %d):", lasheader->laszip->chunk_size);
        else fprintf(file_out, "):");
        for (i = 0; i < (int)lasheader->laszip->num_items; i++) fprintf(file_out, " %s %d", lasheader->laszip->items[i].get_name(), lasheader->laszip->items[i].version);
        fprintf(file_out, "\012");
      }
      if (lasheader->vlr_lastiling)
      {
        fprintf(file_out, "LAStiling (idx %d, lvl %d, sub %d, bbox %g %g %g %g%s%s)\n", 
          lasheader->vlr_lastiling->level_index, 
          lasheader->vlr_lastiling->level,
          lasheader->vlr_lastiling->implicit_levels,
          lasheader->vlr_lastiling->min_x,
          lasheader->vlr_lastiling->min_y,
          lasheader->vlr_lastiling->max_x,
          lasheader->vlr_lastiling->max_y,
          (lasheader->vlr_lastiling->buffer ? ", buffer" : ""),
          (lasheader->vlr_lastiling->reversible ? ", reversible" : ""));
      }
      if (lasheader->vlr_lasoriginal)
      {
        fprintf(file_out, "LASoriginal (npoints %u, bbox %g %g %g %g %g %g)\n", 
          (U32)lasheader->vlr_lasoriginal->number_of_point_records, 
          lasheader->vlr_lasoriginal->min_x,
          lasheader->vlr_lasoriginal->min_y,
          lasheader->vlr_lasoriginal->min_z,
          lasheader->vlr_lasoriginal->max_x,
          lasheader->vlr_lasoriginal->max_y,
          lasheader->vlr_lasoriginal->max_z);
      }
    }

    F64 enlarged_min_x = lasreader->header.min_x - 0.25 * lasreader->header.x_scale_factor;
    F64 enlarged_max_x = lasreader->header.max_x + 0.25 * lasreader->header.x_scale_factor;
    F64 enlarged_min_y = lasreader->header.min_y - 0.25 * lasreader->header.y_scale_factor;
    F64 enlarged_max_y = lasreader->header.max_y + 0.25 * lasreader->header.y_scale_factor;
    F64 enlarged_min_z = lasreader->header.min_z - 0.25 * lasreader->header.z_scale_factor;
    F64 enlarged_max_z = lasreader->header.max_z + 0.25 * lasreader->header.z_scale_factor;
    LASsummary lassummary;

    if (check_points)
    {
      I64 num_first_returns = 0;
      I64 num_intermediate_returns = 0;
      I64 num_last_returns = 0;
      I64 num_single_returns = 0;
      I64 num_all_returns = 0;
      I64 outside_bounding_box = 0;
      LASoccupancyGrid* lasoccupancygrid = 0;

      if (compute_density)
      {
        lasoccupancygrid = new LASoccupancyGrid(horizontal_units > 9001 ? 6.0f : 2.0f);
      }

      if (file_out && !no_min_max) fprintf(file_out, "reporting minimum and maximum for all LAS point record entries ...\012");

      if (subsequence_start) lasreader->seek(subsequence_start);

      while (lasreader->read_point())
      {
        if (lasreader->p_count > subsequence_stop) break;

        if (check_outside)
        {
          if (!lasreader->point.inside_bounding_box(enlarged_min_x, enlarged_min_y, enlarged_min_z, enlarged_max_x, enlarged_max_y, enlarged_max_z))
          {
            outside_bounding_box++;
            if (file_out && report_outside)
            {
              fprintf(file_out, "%u t %g x %g y %g z %g i %d (%d of %d) d %d e %d c %d s %d %u p %d \012", (U32)(lasreader->p_count-1), lasreader->point.get_gps_time(), lasreader->point.get_x(), lasreader->point.get_y(), lasreader->point.get_z(), lasreader->point.get_intensity(), lasreader->point.get_return_number(), lasreader->point.get_number_of_returns(), lasreader->point.get_scan_direction_flag(), lasreader->point.get_edge_of_flight_line(), lasreader->point.get_classification(), lasreader->point.get_scan_angle_rank(), lasreader->point.get_user_data(), lasreader->point.get_point_source_ID());
            }
          }
        }

        lassummary.add(&lasreader->point);

        if (lasoccupancygrid)
        {
          lasoccupancygrid->add(&lasreader->point);
        }

        if (lasreader->point.is_first())
        {
          num_first_returns++;
        }
        if (lasreader->point.is_intermediate())
        {
          num_intermediate_returns++;
        }
        if (lasreader->point.is_last())
        {
          num_last_returns++;
        }
        if (lasreader->point.is_single())
        {
          num_single_returns++;
        }
        num_all_returns++;

        if (lashistogram.active())
        {
          lashistogram.add(&lasreader->point);
        }

#ifdef _WIN32
          if (file_out && progress && (lasreader->p_count % progress) == 0)
          {
            fprintf(file_out, " ... processed %I64d points ...\012", lasreader->p_count);
          }
#else
          if (file_out && progress && (lasreader->p_count % progress) == 0) {
              fprintf(file_out, " ... processed %lld points ...\012", lasreader->p_count);
          }
#endif
      }
      if (file_out && !no_min_max)
      {
        fprintf(file_out, "  X          %10d %10d\012",lassummary.min.get_X(), lassummary.max.get_X());
        fprintf(file_out, "  Y          %10d %10d\012",lassummary.min.get_Y(), lassummary.max.get_Y());
        fprintf(file_out, "  Z          %10d %10d\012",lassummary.min.get_Z(), lassummary.max.get_Z());
        fprintf(file_out, "  intensity  %10d %10d\012",lassummary.min.intensity, lassummary.max.intensity);
        fprintf(file_out, "  return_number       %d %10d\012",lassummary.min.return_number, lassummary.max.return_number);
        fprintf(file_out, "  number_of_returns   %d %10d\012",lassummary.min.number_of_returns, lassummary.max.number_of_returns);
        fprintf(file_out, "  edge_of_flight_line %d %10d\012",lassummary.min.edge_of_flight_line, lassummary.max.edge_of_flight_line);
        fprintf(file_out, "  scan_direction_flag %d %10d\012",lassummary.min.scan_direction_flag, lassummary.max.scan_direction_flag);
        fprintf(file_out, "  classification  %5d %10d\012",lassummary.min.classification, lassummary.max.classification);
        fprintf(file_out, "  scan_angle_rank %5d %10d\012",lassummary.min.scan_angle_rank, lassummary.max.scan_angle_rank);
        fprintf(file_out, "  user_data       %5d %10d\012",lassummary.min.user_data, lassummary.max.user_data);
        fprintf(file_out, "  point_source_ID %5d %10d\012",lassummary.min.point_source_ID, lassummary.max.point_source_ID);
        if (lasreader->point.have_gps_time)
        {
          fprintf(file_out, "  gps_time %f %f\012",lassummary.min.gps_time, lassummary.max.gps_time);
          if ((lasreader->header.global_encoding & 1) == 0)
          {
            if (!no_warnings && (lassummary.min.gps_time < 0.0 || lassummary.max.gps_time > 604800.0))
            {
              fprintf(file_out, "WARNING: range violates GPS week time specified by global encoding bit 0\012");
            }
          }
          else if (gps_week)
          {
            I32 week_min = (I32)(lassummary.min.gps_time/604800.0 + 1653.4391534391534391534391534392);
            I32 week_max = (I32)(lassummary.max.gps_time/604800.0 + 1653.4391534391534391534391534392);
            I32 secs_min = week_min*604800 - 1000000000;
            I32 secs_max = week_max*604800 - 1000000000;
            fprintf(file_out, "  gps_week %d %d\012", week_min, week_max);
            fprintf(file_out, "  gps_secs_of_week %f %f\012", (lassummary.min.gps_time-secs_min), (lassummary.max.gps_time-secs_max));
          }
        }
        if (lasreader->point.have_rgb)
        {
          fprintf(file_out, "  Color R %d %d\012", lassummary.min.rgb[0], lassummary.max.rgb[0]);
          fprintf(file_out, "        G %d %d\012", lassummary.min.rgb[1], lassummary.max.rgb[1]);
          fprintf(file_out, "        B %d %d\012", lassummary.min.rgb[2], lassummary.max.rgb[2]);
        }
        if (lasreader->point.have_nir)
        {
          fprintf(file_out, "      NIR %d %d\012", lassummary.min.rgb[3], lassummary.max.rgb[3]);
        }
        if (lasreader->point.have_wavepacket)
        {
          fprintf(file_out, "  Wavepacket Index    %d %d\012", lassummary.min.wavepacket.getIndex(), lassummary.max.wavepacket.getIndex());
#ifdef _WIN32
          fprintf(file_out, "             Offset   %I64d %I64d\012", lassummary.min.wavepacket.getOffset(), lassummary.max.wavepacket.getOffset());
#else
          fprintf(file_out, "             Offset   %lld %lld\012", lassummary.min.wavepacket.getOffset(), lassummary.max.wavepacket.getOffset());
#endif
          fprintf(file_out, "             Size     %d %d\012", lassummary.min.wavepacket.getSize(), lassummary.max.wavepacket.getSize());
          fprintf(file_out, "             Location %g %g\012", lassummary.min.wavepacket.getLocation(), lassummary.max.wavepacket.getLocation());
          fprintf(file_out, "             Xt       %g %g\012", lassummary.min.wavepacket.getXt(), lassummary.max.wavepacket.getXt());
          fprintf(file_out, "             Yt       %g %g\012", lassummary.min.wavepacket.getYt(), lassummary.max.wavepacket.getYt());
          fprintf(file_out, "             Zt       %g %g\012", lassummary.min.wavepacket.getZt(), lassummary.max.wavepacket.getZt());
        }
        if (lasreader->point.extended_point_type)
        {
          fprintf(file_out, "  extended_return_number     %6d %6d\012", lassummary.min.extended_return_number, lassummary.max.extended_return_number);
          fprintf(file_out, "  extended_number_of_returns %6d %6d\012", lassummary.min.extended_number_of_returns, lassummary.max.extended_number_of_returns);
          fprintf(file_out, "  extended_classification    %6d %6d\012", lassummary.min.extended_classification, lassummary.max.extended_classification);
          fprintf(file_out, "  extended_scan_angle        %6d %6d\012", lassummary.min.extended_scan_angle, lassummary.max.extended_scan_angle);
          fprintf(file_out, "  extended_scanner_channel   %6d %6d\012", lassummary.min.extended_scanner_channel, lassummary.max.extended_scanner_channel);
        }
        if (lasreader->point.extra_bytes_number && lasreader->point.attributer)
        {
          lassummary.min.attributer = lasreader->point.attributer;
          lassummary.max.attributer = lasreader->point.attributer;
          I32 a;
          for (a = 0; a < lasreader->point.attributer->number_attributes; a++)
          {
            fprintf(file_out, "  attribute%d %10g %10g  ('%s')\012", a, lassummary.min.get_attribute_as_float(a), lassummary.max.get_attribute_as_float(a), lasreader->point.attributer->get_attribute_name(a));
          }
          lassummary.min.attributer = 0;
          lassummary.max.attributer = 0;
        }
        if (((number_of_point_records == 0) && (lasheader->number_of_point_records > 0)) || ((number_of_points_by_return0 == 0) && (lasheader->number_of_points_by_return[0] > 0)))
        {
          fprintf(file_out, "re-reporting LAS header entries populated during read pass:\012");
          if ((number_of_point_records == 0) && (lasheader->number_of_point_records > 0)) fprintf(file_out, "  number of point records    %u\012", lasheader->number_of_point_records);
          if ((number_of_points_by_return0 == 0) && (lasheader->number_of_points_by_return[0] > 0)) fprintf(file_out, "  number of points by return %u %u %u %u %u\012", lasheader->number_of_points_by_return[0], lasheader->number_of_points_by_return[1], lasheader->number_of_points_by_return[2], lasheader->number_of_points_by_return[3], lasheader->number_of_points_by_return[4]);
          fprintf(file_out, "  min x y z                  "); lidardouble2string(printstring, lasheader->min_x, lasheader->x_scale_factor); fprintf(file_out, "%s ", printstring); lidardouble2string(printstring, lasheader->min_y, lasheader->y_scale_factor); fprintf(file_out, "%s ", printstring); lidardouble2string(printstring, lasheader->min_z, lasheader->z_scale_factor); fprintf(file_out, "%s\012", printstring);
          fprintf(file_out, "  max x y z                  "); lidardouble2string(printstring, lasheader->max_x, lasheader->x_scale_factor); fprintf(file_out, "%s ", printstring); lidardouble2string(printstring, lasheader->max_y, lasheader->y_scale_factor); fprintf(file_out, "%s ", printstring); lidardouble2string(printstring, lasheader->max_z, lasheader->z_scale_factor); fprintf(file_out, "%s\012", printstring);
        }
      }
      if (!no_warnings && file_out && outside_bounding_box)
      {
#ifdef _WIN32
        fprintf(file_out, "WARNING: %I64d points outside of header bounding box\012", outside_bounding_box);
#else
        fprintf(file_out, "WARNING: %lld points outside of header bounding box\012", outside_bounding_box);
#endif
      }
      if (!no_warnings && file_out && lassummary.has_fluff())
      {
        fprintf(file_out, "WARNING: there is coordinate resolution fluff (x10) in %s%s%s\012", (lassummary.has_fluff(0) ? "X" : ""), (lassummary.has_fluff(1) ? "Y" : ""), (lassummary.has_fluff(2) ? "Z" : ""));
        if (lassummary.has_serious_fluff())
        {
          fprintf(file_out, "WARNING: there is serious coordinate resolution fluff (x100) in %s%s%s\012", (lassummary.has_serious_fluff(0) ? "X" : ""), (lassummary.has_serious_fluff(1) ? "Y" : ""), (lassummary.has_serious_fluff(2) ? "Z" : ""));
          if (lassummary.has_very_serious_fluff())
          {
            fprintf(file_out, "WARNING: there is very serious coordinate resolution fluff (x1000) in %s%s%s\012", (lassummary.has_very_serious_fluff(0) ? "X" : ""), (lassummary.has_very_serious_fluff(1) ? "Y" : ""), (lassummary.has_very_serious_fluff(2) ? "Z" : ""));
            if (lassummary.has_extremely_serious_fluff())
            {
              fprintf(file_out, "WARNING: there is extremely serious coordinate resolution fluff (x10000) in %s%s%s\012", (lassummary.has_extremely_serious_fluff(0) ? "X" : ""), (lassummary.has_extremely_serious_fluff(1) ? "Y" : ""), (lassummary.has_extremely_serious_fluff(2) ? "Z" : ""));
            }
          }
        }
      }
      if (file_out && !no_returns)
      {
#ifdef _WIN32
        fprintf(file_out, "number of first returns:        %I64d\012", num_first_returns);
        fprintf(file_out, "number of intermediate returns: %I64d\012", num_intermediate_returns);
        fprintf(file_out, "number of last returns:         %I64d\012", num_last_returns);
        fprintf(file_out, "number of single returns:       %I64d\012", num_single_returns);
#else
        fprintf(file_out, "number of first returns:        %lld\012", num_first_returns);
        fprintf(file_out, "number of intermediate returns: %lld\012", num_intermediate_returns);
        fprintf(file_out, "number of last returns:         %lld\012", num_last_returns);
        fprintf(file_out, "number of single returns:       %lld\012", num_single_returns);
#endif
      }
      if (file_out && lasoccupancygrid)
      {
        if (num_last_returns)
        {
          if (horizontal_units == 9001)
          {
            fprintf(file_out, "covered area in square meters/kilometers: %d/%.2f\012", 4*lasoccupancygrid->get_num_occupied(), 0.000004*lasoccupancygrid->get_num_occupied());
            fprintf(file_out, "point density: all returns %.2f last only %.2f (per square meter)\012", ((F64)num_all_returns/(4.0*lasoccupancygrid->get_num_occupied())), ((F64)num_last_returns/(4.0*lasoccupancygrid->get_num_occupied())));
            fprintf(file_out, "      spacing: all returns %.2f last only %.2f (in meters)\012", sqrt(4.0*lasoccupancygrid->get_num_occupied()/(F64)num_all_returns), sqrt(4.0*lasoccupancygrid->get_num_occupied()/(F64)num_last_returns));
          }
          else if (horizontal_units == 9002)
          {
            fprintf(file_out, "covered area in square feet/miles: %d/%.2f\012", 36*lasoccupancygrid->get_num_occupied(),1.2913223e-6*lasoccupancygrid->get_num_occupied());
            fprintf(file_out, "point density: all returns %.2f last only %.2f (per square foot)\012", ((F64)num_all_returns/(36.0*lasoccupancygrid->get_num_occupied())), ((F64)num_last_returns/(36.0*lasoccupancygrid->get_num_occupied())));
            fprintf(file_out, "      spacing: all returns %.2f last only %.2f (in feet)\012", sqrt(36.0*lasoccupancygrid->get_num_occupied()/(F64)num_all_returns), sqrt(36.0*lasoccupancygrid->get_num_occupied()/(F64)num_last_returns));
          }
          else if (horizontal_units == 9003)
          {
            fprintf(file_out, "covered area in square survey feet: %d\012", 36*lasoccupancygrid->get_num_occupied());
            fprintf(file_out, "point density: all returns %.2f last only %.2f (per square survey foot)\012", ((F64)num_all_returns/(36.0*lasoccupancygrid->get_num_occupied())), ((F64)num_last_returns/(36.0*lasoccupancygrid->get_num_occupied())));
            fprintf(file_out, "      spacing: all returns %.2f last only %.2f (in survey feet)\012", sqrt(36.0*lasoccupancygrid->get_num_occupied()/(F64)num_all_returns), sqrt(36.0*lasoccupancygrid->get_num_occupied()/(F64)num_last_returns));
          }
          else
          {
            fprintf(file_out, "covered area in square units/kilounits: %d/%.2f\012", 4*lasoccupancygrid->get_num_occupied(), 0.000004*lasoccupancygrid->get_num_occupied());
            fprintf(file_out, "point density: all returns %.2f last only %.2f (per square units)\012", ((F64)num_all_returns/(4.0*lasoccupancygrid->get_num_occupied())), ((F64)num_last_returns/(4.0*lasoccupancygrid->get_num_occupied())));
            fprintf(file_out, "      spacing: all returns %.2f last only %.2f (in units)\012", sqrt(4.0*lasoccupancygrid->get_num_occupied()/(F64)num_all_returns), sqrt(4.0*lasoccupancygrid->get_num_occupied()/(F64)num_last_returns));
          }
        }
        delete lasoccupancygrid;
      }
    }

    lasreader->close();

    FILE* file = 0;

    if (repair_bb || repair_counters)
    {
      if (lasreadopener.is_piped())
      {
        fprintf(stderr, "ERROR: cannot repair header of piped input\n");
        repair_bb = repair_counters = false;
      }
      else if (lasreadopener.is_merged())
      {
        fprintf(stderr, "ERROR: cannot repair header of merged input\n");
        repair_bb = repair_counters = false;
      }
      else if (lasreadopener.is_buffered())
      {
        fprintf(stderr, "ERROR: cannot repair header of buffered input\n");
        repair_bb = repair_counters = false;
      }
      else if (lasreader->get_format() > LAS_TOOLS_FORMAT_LAZ)
      {
        fprintf(stderr, "ERROR: can only repair header for LAS or LAZ files, not for '%s'\n", lasreadopener.get_file_name());
        repair_bb = repair_counters = false;
      }
      file = fopen(lasreadopener.get_file_name(), "rb+");
      if (file == 0)
      {
        fprintf (stderr, "ERROR: could not reopen file '%s' for repair of header\n", lasreadopener.get_file_name());
        repair_bb = repair_counters = false;
      }
    }

    if (check_points)
    {

      if ((lasheader->point_data_format < 6) && (lassummary.number_of_point_records != lasheader->number_of_point_records))
      {
        if (repair_counters)
        {
          if (lassummary.number_of_point_records <= U32_MAX)
          {
            U32 number_of_point_records = (U32)lassummary.number_of_point_records;;
            fseek(file, 107, SEEK_SET);
            fwrite(&number_of_point_records, sizeof(U32), 1, file);
            if (file_out)
            {
              fprintf(file_out, "WARNING: real number of point records (%u) is different from header entry (%u). it was repaired. \n", number_of_point_records, lasheader->number_of_point_records);
            }
          }
          else if (lasheader->version_minor < 4)
          {
            if (file_out)
            {
#ifdef _WIN32
              fprintf(file_out, "WARNING: real number of point records (%I64d) exceeds 4,294,967,295. cannot repair. too big.\n", lassummary.number_of_point_records);
#else
              fprintf(file_out, "WARNING: real number of point records (%lld) exceeds 4,294,967,295. cannot repair. too big.\n", lassummary.number_of_point_records);
#endif
            }
          }
          else if (lasheader->number_of_point_records != 0)
          {
            U32 number_of_point_records = 0;
            fseek(file, 107, SEEK_SET);
            fwrite(&number_of_point_records, sizeof(U32), 1, file);
            if (file_out)
            {
#ifdef _WIN32
              fprintf(file_out, "WARNING: real number of point records (%I64d) exceeds 4,294,967,295. but header entry is %u instead zero. it was repaired.\n", lassummary.number_of_point_records, lasheader->number_of_point_records);
#else
              fprintf(file_out, "WARNING: real number of point records (%lld) exceeds 4,294,967,295. but header entry is %u instead zero. it was repaired.\n", lassummary.number_of_point_records, lasheader->number_of_point_records);
#endif
            }
          }
          else
          {
            if (file_out)
            {
              fprintf(file_out, "number of point records in header is correct.\n");
            }
          }
        }
        else
        {
          if (!no_warnings && file_out)
          {
            if (lassummary.number_of_point_records <= U32_MAX)
            {
#ifdef _WIN32
              fprintf(file_out, "WARNING: real number of point records (%I64d) is different from header entry (%u).\n", lassummary.number_of_point_records, lasheader->number_of_point_records);
#else
              fprintf(file_out, "WARNING: real number of point records (%lld) is different from header entry (%u).\n", lassummary.number_of_point_records, lasheader->number_of_point_records);
#endif
            }
            else if (lasheader->version_minor < 4)
            {
#ifdef _WIN32
              fprintf(file_out, "WARNING: real number of point records (%I64d) exceeds 4,294,967,295.\n", lassummary.number_of_point_records);
#else
              fprintf(file_out, "WARNING: real number of point records (%lld) exceeds 4,294,967,295.\n", lassummary.number_of_point_records);
#endif
            }
            else if (lasheader->number_of_point_records != 0)
            {
#ifdef _WIN32
              fprintf(file_out, "WARNING: real number of point records (%I64d) exceeds 4,294,967,295. but header entry is %u instead of zero.\n", lassummary.number_of_point_records, lasheader->number_of_point_records);
#else
              fprintf(file_out, "WARNING: real number of point records (%lld) exceeds 4,294,967,295. but header entry is %u instead of zero.\n", lassummary.number_of_point_records, lasheader->number_of_point_records);
#endif
            }
          }
        }
      }
      else if ((lasheader->point_data_format >= 6) && (lasheader->number_of_point_records != 0))
      {
        if (repair_counters)
        {
          U32 number_of_point_records = 0;
          fseek(file, 107, SEEK_SET);
          fwrite(&number_of_point_records, sizeof(U32), 1, file);
        }
        if (!no_warnings && file_out)
        {
          fprintf(file_out, "WARNING: point type is %d but (legacy) number of point records in header is %u instead zero.%s\n", lasheader->point_data_format, lasheader->number_of_point_records, (repair_counters ? "it was repaired." : ""));
        }
      }
      else
      {
        if (repair_counters)
        {
          if (file_out)
          {
            fprintf(file_out, "number of point records in header is correct.\n");
          }
        }
      }

      if (lasheader->version_minor > 3)
      {
        if (lassummary.number_of_point_records != (I64)lasheader->extended_number_of_point_records)
        {
          if (repair_counters)
          {
            I64 extended_number_of_point_records = lassummary.number_of_point_records;
            fseek(file, 235 + 12, SEEK_SET);
            fwrite(&extended_number_of_point_records, sizeof(I64), 1, file);
          }
          if (!no_warnings && file_out)
          {
#ifdef _WIN32
            fprintf(file_out, "WARNING: real number of point records (%I64d) is different from extended header entry (%I64d).%s\n", lassummary.number_of_point_records, lasheader->extended_number_of_point_records, (repair_counters ? " it was repaired." : ""));
#else
            fprintf(file_out, "WARNING: real number of point records (%lld) is different from extended header entry (%lld).%s\n", lassummary.number_of_point_records, lasheader->extended_number_of_point_records, (repair_counters ? " it was repaired." : ""));
#endif
          }
        }
        else
        {
          if (repair_counters)
          {
            if (file_out)
            {
              fprintf(file_out, "extended number of point records in header is correct.\n");
            }
          }
        }
      }

      bool was_set = false;
      for (i = 1; i < 6; i++) if (lasheader->number_of_points_by_return[i-1]) was_set = true;

      bool wrong_entry = false;

      U32 number_of_points_by_return[5];
      for (i = 1; i < 6; i++)
      {
        if ((lasheader->point_data_format < 6) && ((I64)(lasheader->number_of_points_by_return[i-1]) != lassummary.number_of_points_by_return[i]))
        {
          if (lassummary.number_of_points_by_return[i] <= U32_MAX)
          {
            number_of_points_by_return[i-1] = (U32)lassummary.number_of_points_by_return[i];
            wrong_entry = true;
            if (!no_warnings && file_out)
            {
              if (was_set)
              {
                fprintf(file_out, "WARNING: for return %d real number of points by return (%u) is different from header entry (%u).%s\n", i, number_of_points_by_return[i-1], lasheader->number_of_points_by_return[i-1], (repair_counters ? " it was repaired." : ""));
              }
              else
              {
                fprintf(file_out, "WARNING: for return %d real number of points by return is %u but header entry was not set.%s\n", i, number_of_points_by_return[i-1], (repair_counters ? " it was repaired." : ""));
              }
            }
          }
          else if (lasheader->version_minor < 4)
          {
            if (!no_warnings && file_out)
            {
#ifdef _WIN32
              fprintf(file_out, "WARNING: for return %d real number of points by return (%I64d) exceeds 4,294,967,295.%s\n", i, lassummary.number_of_points_by_return[i], (repair_counters ? " cannot repair. too big." : ""));
#else
              fprintf(file_out, "WARNING: for return %d real number of points by return (%lld) exceeds 4,294,967,295.%s\n", i, lassummary.number_of_points_by_return[i], (repair_counters ? " cannot repair. too big." : ""));
#endif
            }
          }
          else if (lasheader->number_of_points_by_return[i-1] != 0)
          {
            number_of_points_by_return[i-1] = 0;
            wrong_entry = true;
            if (!no_warnings && file_out)
            {
#ifdef _WIN32
              fprintf(file_out, "WARNING: for return %d real number of points by return (%I64d) exceeds 4,294,967,295. but header entry is %u instead zero.%s\n", i, lassummary.number_of_points_by_return[i], lasheader->number_of_points_by_return[i-1], (repair_counters ? " it was repaired." : ""));
#else
              fprintf(file_out, "WARNING: for return %d real number of points by return (%lld) exceeds 4,294,967,295. but header entry is %u instead zero.%s\n", i, lassummary.number_of_points_by_return[i], lasheader->number_of_points_by_return[i-1], (repair_counters ? " it was repaired." : ""));
#endif
            }
          }
          else
          {
            number_of_points_by_return[i-1] = 0;
          }
        }
        else if ((lasheader->point_data_format >= 6) && (lasheader->number_of_points_by_return[i-1] != 0))
        {
          number_of_points_by_return[i-1] = 0;
          wrong_entry = true;
          if (!no_warnings && file_out)
          {
            fprintf(file_out, "WARNING: point type is %d but (legacy) number of points by return [%d] in header is %u instead zero.%s\n", lasheader->point_data_format, i, lasheader->number_of_points_by_return[i-1], (repair_counters ? "it was repaired." : ""));
          }
        }
        else
        {
          number_of_points_by_return[i-1] = (U32)lassummary.number_of_points_by_return[i];
        }
      }

      if (repair_counters)
      {
        if (wrong_entry)
        {
          fseek(file, 111, SEEK_SET);
          fwrite(&(number_of_points_by_return[0]), sizeof(U32), 5, file);
        }
        else if (file_out)
        {
          fprintf(file_out, "number of points by return in header is correct.\n");
        }
      }

      if (lasheader->version_minor > 3)
      {
        bool was_set = false;
        for (i = 1; i < 15; i++) if (lasheader->extended_number_of_points_by_return[i-1]) was_set = true;

        bool wrong_entry = false;

        I64 extended_number_of_points_by_return[15];

        for (i = 1; i < 16; i++)
        {
          extended_number_of_points_by_return[i-1] = lassummary.number_of_points_by_return[i];
          if ((I64)lasheader->extended_number_of_points_by_return[i-1] != lassummary.number_of_points_by_return[i])
          {
            wrong_entry = true;
            if (!no_warnings && file_out)
            {
              if (was_set)
              {
#ifdef _WIN32
                fprintf(file_out, "WARNING: real extended number of points by return [%d] is %I64d - different from header entry %I64d.%s\n", i, lassummary.number_of_points_by_return[i], lasheader->extended_number_of_points_by_return[i-1], (repair_counters ? " it was repaired." : ""));
#else
                fprintf(file_out, "WARNING: real extended number of points by return [%d] is %lld - different from header entry %lld.%s\n", i, lassummary.number_of_points_by_return[i], lasheader->extended_number_of_points_by_return[i-1], (repair_counters ? " it was repaired." : ""));
#endif
              }
              else
              {
#ifdef _WIN32
                fprintf(file_out, "WARNING: real extended number of points by return [%d] is %I64d but header entry was not set.%s\n", i, lassummary.number_of_points_by_return[i], (repair_counters ? " it was repaired." : ""));
#else
                fprintf(file_out, "WARNING: real extended number of points by return [%d] is %lld but header entry was not set.%s\n", i, lassummary.number_of_points_by_return[i], (repair_counters ? " it was repaired." : ""));
#endif
              }
            }
          }
        }

        if (repair_counters)
        {
          if (wrong_entry)
          {
            fseek(file, 235 + 20, SEEK_SET);
            fwrite(&(extended_number_of_points_by_return[0]), sizeof(I64), 15, file);
          }
          else if (file_out)
          {
            fprintf(file_out, "extended number of points by return in header is correct.\n");
          }
        }
      }

      if (!no_warnings && file_out && !no_returns)
      {
#ifdef _WIN32
        if (lassummary.number_of_points_by_return[0]) fprintf(file_out, "WARNING: there %s %I64d point%s with return number 0\n", (lassummary.number_of_points_by_return[0] > 1 ? "are" : "is"), lassummary.number_of_points_by_return[0], (lassummary.number_of_points_by_return[0] > 1 ? "s" : ""));
        if (lasheader->version_minor < 4)
        {
          if (lassummary.number_of_points_by_return[6]) fprintf(file_out, "WARNING: there %s %I64d point%s with return number 6\n", (lassummary.number_of_points_by_return[6] > 1 ? "are" : "is"), lassummary.number_of_points_by_return[6], (lassummary.number_of_points_by_return[6] > 1 ? "s" : "")); 
          if (lassummary.number_of_points_by_return[7]) fprintf(file_out, "WARNING: there %s %I64d point%s with return number 7\n", (lassummary.number_of_points_by_return[7] > 1 ? "are" : "is"), lassummary.number_of_points_by_return[7], (lassummary.number_of_points_by_return[7] > 1 ? "s" : "")); 
        }
#else
        if (lassummary.number_of_points_by_return[0]) fprintf(file_out, "WARNING: there %s %lld point%s with return number 0\n", (lassummary.number_of_points_by_return[0] > 1 ? "are" : "is"), lassummary.number_of_points_by_return[0], (lassummary.number_of_points_by_return[0] > 1 ? "s" : "")); 
        if (lasheader->version_minor < 4)
        {
          if (lassummary.number_of_points_by_return[6]) fprintf(file_out, "WARNING: there %s %lld point%s with return number 6\n", (lassummary.number_of_points_by_return[6] > 1 ? "are" : "is"), lassummary.number_of_points_by_return[6], (lassummary.number_of_points_by_return[6] > 1 ? "s" : ""));
          if (lassummary.number_of_points_by_return[7]) fprintf(file_out, "WARNING: there %s %lld point%s with return number 7\n", (lassummary.number_of_points_by_return[7] > 1 ? "are" : "is"), lassummary.number_of_points_by_return[7], (lassummary.number_of_points_by_return[7] > 1 ? "s" : ""));
        }
#endif

        wrong_entry = false;

        if (lasheader->version_minor > 3)
        {
          for (i = 1; i < 16; i++) if (lassummary.number_of_returns[i]) wrong_entry = true;
          if (wrong_entry)
          {
           fprintf(file_out, "overview over extended number of returns of given pulse:"); 
#ifdef _WIN32
            for (i = 1; i < 16; i++) fprintf(file_out, " %I64d", lassummary.number_of_returns[i]);
#else
            for (i = 1; i < 16; i++) fprintf(file_out, " %lld", lassummary.number_of_returns[i]);
#endif
            fprintf(file_out, "\n"); 
          }
        }
        else
        {
          for (i = 1; i < 8; i++) if (lassummary.number_of_returns[i]) wrong_entry = true;
          if (wrong_entry)
          {
           fprintf(file_out, "overview over number of returns of given pulse:"); 
#ifdef _WIN32
            for (i = 1; i < 8; i++) fprintf(file_out, " %I64d", lassummary.number_of_returns[i]);
#else
            for (i = 1; i < 8; i++) fprintf(file_out, " %lld", lassummary.number_of_returns[i]);
#endif
            fprintf(file_out, "\n"); 
          }
        }

#ifdef _WIN32
        if (lassummary.number_of_returns[0]) fprintf(file_out, "WARNING: there are %I64d points with a number of returns of given pulse of 0\n", lassummary.number_of_returns[0]); 
#else
        if (lassummary.number_of_returns[0]) fprintf(file_out, "WARNING: there are %lld points with a number of returns of given pulse of 0\n", lassummary.number_of_returns[0]); 
#endif
      }

      if (file_out && !no_min_max)
      {
        wrong_entry = false;
        for (i = 0; i < 32; i++) if (lassummary.classification[i]) wrong_entry = true;
        if (lassummary.classification_synthetic || lassummary.classification_keypoint ||  lassummary.classification_withheld) wrong_entry = true;

        if (wrong_entry)
        {
          fprintf(file_out, "histogram of classification of points:\n"); 
#ifdef _WIN32
          for (i = 0; i < 32; i++) if (lassummary.classification[i]) fprintf(file_out, " %15I64d  %s (%u)\n", lassummary.classification[i], LASpointClassification[i], i);
          if (lassummary.classification_synthetic) fprintf(file_out, " +-> flagged as synthetic: %I64d\n", lassummary.classification_synthetic);
          if (lassummary.classification_keypoint) fprintf(file_out,  " +-> flagged as keypoints: %I64d\n", lassummary.classification_keypoint);
          if (lassummary.classification_withheld) fprintf(file_out,  " +-> flagged as withheld:  %I64d\n", lassummary.classification_withheld);
#else
          for (i = 0; i < 32; i++) if (lassummary.classification[i]) fprintf(file_out, " %15lld  %s (%u)\n", lassummary.classification[i], LASpointClassification[i], i);
          if (lassummary.classification_synthetic) fprintf(file_out, " +-> flagged as synthetic: %lld\n", lassummary.classification_synthetic);
          if (lassummary.classification_keypoint) fprintf(file_out,  " +-> flagged as keypoints: %lld\n", lassummary.classification_keypoint);
          if (lassummary.classification_withheld) fprintf(file_out,  " +-> flagged as withheld:  %lld\n", lassummary.classification_withheld);
#endif
        }

        if (lasreader->point.extended_point_type)
        {
#ifdef _WIN32
          if (lassummary.classification_extended_overlap) fprintf(file_out, " +-> flagged as extended overlap: %I64d\n", lassummary.classification_extended_overlap);
#else
          if (lassummary.classification_extended_overlap) fprintf(file_out, " +-> flagged as extended overlap: %lld\n", lassummary.classification_extended_overlap);
#endif

          wrong_entry = false;
          for (i = 32; i < 256; i++) if (lassummary.extended_classification[i]) wrong_entry = true;

          if (wrong_entry)
          {
            fprintf(file_out, "histogram of extended classification of points:\n"); 
  #ifdef _WIN32
            for (i = 32; i < 256; i++) if (lassummary.extended_classification[i]) fprintf(file_out, " %15I64d  extended classification (%u)\n", lassummary.extended_classification[i], i);
  #else
            for (i = 32; i < 256; i++) if (lassummary.extended_classification[i]) fprintf(file_out, " %15lld  extended classification (%u)\n", lassummary.extended_classification[i], i);
  #endif
          }
        }
      }

      if (lashistogram.active())
      {
        lashistogram.report(file_out);
        lashistogram.reset();
      }

      double value;
      if (repair_bb)
      {
        wrong_entry = false;
        if (lasheader->get_x(lassummary.max.get_X()) != lasheader->max_x) wrong_entry = true;
        if (lasheader->get_x(lassummary.min.get_X()) != lasheader->min_x) wrong_entry = true;
        if (lasheader->get_y(lassummary.max.get_Y()) != lasheader->max_y) wrong_entry = true;
        if (lasheader->get_y(lassummary.min.get_Y()) != lasheader->min_y) wrong_entry = true;
        if (lasheader->get_z(lassummary.max.get_Z()) != lasheader->max_z) wrong_entry = true;
        if (lasheader->get_z(lassummary.min.get_Z()) != lasheader->min_z) wrong_entry = true;
        if (wrong_entry)
        {
          fseek(file, 179, SEEK_SET);
          value = lasheader->get_x(lassummary.max.get_X()); fwrite(&value, sizeof(double), 1, file);
          value = lasheader->get_x(lassummary.min.get_X()); fwrite(&value, sizeof(double), 1, file);
          value = lasheader->get_y(lassummary.max.get_Y()); fwrite(&value, sizeof(double), 1, file);
          value = lasheader->get_y(lassummary.min.get_Y()); fwrite(&value, sizeof(double), 1, file);
          value = lasheader->get_z(lassummary.max.get_Z()); fwrite(&value, sizeof(double), 1, file);
          value = lasheader->get_z(lassummary.min.get_Z()); fwrite(&value, sizeof(double), 1, file);
          if (file_out) fprintf(file_out, "bounding box was repaired.\n");
        }
        else
        {
          if (file_out) fprintf(file_out, "bounding box is correct.\n");
        }
      }
      else
      {
        value = lasheader->get_x(lassummary.max.get_X());
        if (value > enlarged_max_x)
        {
          if (!no_warnings && file_out) fprintf(file_out, "WARNING: real max x larger than header max x by %lf\n", value - lasheader->max_x);
        }
        value = lasheader->get_x(lassummary.min.get_X());
        if (value < enlarged_min_x)
        {
          if (!no_warnings && file_out) fprintf(file_out, "WARNING: real min x smaller than header min x by %lf\n", lasheader->min_x - value);
        }
        value = lasheader->get_y(lassummary.max.get_Y());
        if (value > enlarged_max_y)
        {
          if (!no_warnings && file_out) fprintf(file_out, "WARNING: real max y larger than header max y by %lf\n", value - lasheader->max_y);
        }
        value = lasheader->get_y(lassummary.min.get_Y());
        if (value < enlarged_min_y)
        {
          if (!no_warnings && file_out) fprintf(file_out, "WARNING: real min y smaller than header min y by %lf\n", lasheader->min_y - value);
        }
        value = lasheader->get_z(lassummary.max.get_Z());
        if (value > enlarged_max_z)
        {
          if (!no_warnings && file_out) fprintf(file_out, "WARNING: real max z larger than header max z by %lf\n", value - lasheader->max_z);
        }
        value = lasheader->get_z(lassummary.min.get_Z());
        if (value < enlarged_min_z)
        {
          if (!no_warnings && file_out) fprintf(file_out, "WARNING: real min z smaller than header min z by %lf\n", lasheader->min_z - value);
        }
      }
    }

    if (file_out && (file_out != stdout) && (file_out != stderr)) fclose(file_out);
    laswriteopener.set_file_name(0);

    delete lasreader;
    if (file) fclose(file);
  }

  if (set_system_identifier) delete [] set_system_identifier;
  if (set_generating_software) delete [] set_generating_software;
  if (set_bounding_box) delete [] set_bounding_box;
  if (set_offset) delete [] set_offset;
  if (set_scale) delete [] set_scale;

  byebye(false, wait || (argc==1));

  return 0;
}
﻿/*
===============================================================================

  FILE:  lasinfo.cpp

  CONTENTS:

    This tool reads a LIDAR file in LAS or LAZ format and prints out the info
    from the standard header. It also prints out info from any variable length
    headers and gives detailed info on any geokeys that may be present (this
    can be disabled with the '-no_vrls' flag). The real bounding box of the
    points is computed and compared with the bounding box specified in the header
    (this can be disabled with the '-no_check' flag). It is also possible to
    change or repair some aspects of the header 

  PROGRAMMERS:

    martin.isenburg@rapidlasso.com  -  http://rapidlasso.com
  
  COPYRIGHT:
  
    (c) 2007-13, martin isenburg, rapidlasso - fast tools to catch reality

    This is free software; you can redistribute and/or modify it under the
    terms of the GNU Lesser General Licence as published by the Free Software
    Foundation. See the LICENSE.txt file for more information.

    This software is distributed WITHOUT ANY WARRANTY and without even the
    implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

  CHANGE HISTORY:

    14 October 2017 -- WARN when bounding box miss-matches coordinate resolution
    16 May 2015 -- new option '-set_GUID F794F8A4-A23E-421E-A134-ACF7754E1C54'
     9 July 2012 -- fixed crash that occured when input had a corrupt VLRs
     7 January 2012 -- set bounding box / file source id / point type & size / ...
     6 January 2012 -- make area/density optional
     5 September 2011 -- also compute total area covered and point densities
    26 January 2011 -- added LAStransform because it allows quick previews
    21 January 2011 -- added LASreadOpener and reading of multiple LAS files 
     4 January 2011 -- added the LASfilter to drop or keep points 
    10 July 2009 -- '-auto_date' sets the day/year from the file creation date
    12 March 2009 -- updated to ask for input if started without arguments 
     9 March 2009 -- added output for size of user-defined header data
    17 September 2008 -- updated to deal with LAS format version 1.2
    13 July 2007 -- added the option to "repair" the header and change items
    11 June 2007 -- fixed number of return counts after Vinton found another bug
     6 June 2007 -- added lidardouble2string() after Vinton Valentine's bug report
    25 March 2007 -- sitting at the Pacific Coffee after doing the escalators

===============================================================================
*/

#include "geoprojectionconverter.hpp"
#include "lasreader.hpp"
#include "laszip_decompress_selective_v3.hpp"
#include "lasutility.hpp"
#include "laswriter.hpp"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#ifdef _WIN32
#include <windows.h>
#endif

static const char * LASpointClassification [32] = {
  "never classified",
  "unclassified",
  "ground",
  "low vegetation",
  "medium vegetation",
  "high vegetation",
  "building",
  "noise",
  "keypoint",
  "water",
  "rail",
  "road surface",
  "overlap",
  "wire guard",
  "wire conductor",
  "tower",
  "wire connector",
  "bridge deck",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition",
  "Reserved for ASPRS Definition"
};

void usage(bool error=false, bool wait=false)
{
  fprintf(stderr,"usage:\n");
  fprintf(stderr,"lasinfo -i lidar.las\n");
  fprintf(stderr,"lasinfo -i lidar.las -compute_density -o lidar_info.txt\n");
  fprintf(stderr,"lasinfo -i *.las\n");
  fprintf(stderr,"lasinfo -i *.las -single -otxt\n");
  fprintf(stderr,"lasinfo -no_header -no_vlrs -i lidar.laz\n");
  fprintf(stderr,"lasinfo -nv -nc -stdout -i lidar.las\n");
  fprintf(stderr,"lasinfo -nv -nc -stdout -i *.laz -single | grep version\n");
  fprintf(stderr,"lasinfo -i *.laz -subseq 100000 100100 -histo user_data 8\n");
  fprintf(stderr,"lasinfo -i *.las -repair\n");
  fprintf(stderr,"lasinfo -i *.laz -repair_bb -set_file_creation 8 2007\n");
  fprintf(stderr,"lasinfo -i *.las -repair_counters -set_version 1.2\n");
  fprintf(stderr,"lasinfo -i *.laz -set_system_identifier \"hello world!\" -set_generating_software \"this is a test (-:\"\n");
  if (wait)
  {
    fprintf(stderr,"<press ENTER>\n");
    getc(stdin);
  }
  exit(error);
}

static void byebye(bool error=false, bool wait=false)
{
  if (wait)
  {
    fprintf(stderr,"<press ENTER>\n");
    getc(stdin);
  }
  exit(error);
}

static inline void VecUpdateMinMax3dv(double min[3], double max[3], const double v[3])
{
  if (v[0]<min[0]) min[0]=v[0]; else if (v[0]>max[0]) max[0]=v[0];
  if (v[1]<min[1]) min[1]=v[1]; else if (v[1]>max[1]) max[1]=v[1];
  if (v[2]<min[2]) min[2]=v[2]; else if (v[2]>max[2]) max[2]=v[2];
}

static inline void VecCopy3dv(double v[3], const double a[3])
{
  v[0] = a[0];
  v[1] = a[1];
  v[2] = a[2];
}

static int lidardouble2string(char* string, double value)
{
  int len;
  len = sprintf(string, "%.15f", value) - 1;
  while (string[len] == '0') len--;
  if (string[len] != '.') len++;
  string[len] = '\0';
  return len;
}

static I32 lidardouble2string(char* string, double value, double precision)
{
  if (precision == 0.1)
    sprintf(string, "%.1f", value);
  else if (precision == 0.01)
    sprintf(string, "%.2f", value);
  else if (precision == 0.001 || precision == 0.002 || precision == 0.005 || precision == 0.025) 
    sprintf(string, "%.3f", value);
  else if (precision == 0.0001 || precision == 0.0002 || precision == 0.0005 || precision == 0.0025)
    sprintf(string, "%.4f", value);
  else if (precision == 0.00001 || precision == 0.00002 || precision == 0.00005 || precision == 0.00025)
    sprintf(string, "%.5f", value);
  else if (precision == 0.000001)
    sprintf(string, "%.6f", value);
  else if (precision == 0.0000001)
    sprintf(string, "%.7f", value);
  else if (precision == 0.00000001)
    sprintf(string, "%.8f", value);
  else
    return lidardouble2string(string, value);
  return (I32)strlen(string)-1;
}

static bool valid_resolution(F64 coordinate, F64 offset, F64 scale_factor)
{
  F64 coordinate_without_offset = coordinate - offset;
  F64 fixed_precision_multiplier = coordinate_without_offset / scale_factor;
  I64 quantized_fixed_precision_multiplier = I64_QUANTIZE(fixed_precision_multiplier);
  if ((fabs(fixed_precision_multiplier - quantized_fixed_precision_multiplier)) < 0.001)
  {
    return true;
  }
  return false;
}

#ifdef COMPILE_WITH_GUI
extern int lasinfo_gui(int argc, char *argv[], LASreadOpener* lasreadopener);
#endif

#ifdef COMPILE_WITH_MULTI_CORE
extern int lasinfo_multi_core(int argc, char *argv[], LASreadOpener* lasreadopener, LAShistogram* lashistogram, LASwriteOpener* laswriteopener, int cores, BOOL cpu64);
#endif

int main(int argc, char *argv[])
{
  int i;
#ifdef COMPILE_WITH_GUI
  bool gui = false;
#endif
#ifdef COMPILE_WITH_MULTI_CORE
  I32 cores = 1;
  BOOL cpu64 = FALSE;
#endif
  bool wait = false;
  bool verbose = false;
  bool no_header = false;
  bool no_variable_header = false;
  bool no_returns = false;
  bool no_min_max = false;
  bool no_warnings = false;
  bool check_points = true;
  bool compute_density = false;
  bool gps_week = false;
  bool check_outside = true;
  bool report_outside = false;
  bool suppress_z = false;
  bool suppress_classification = false;
  bool suppress_flags = false;
  bool suppress_intensity = false;
  bool suppress_user_data = false;
  bool suppress_point_source = false;
  bool suppress_scan_angle = false;
  bool suppress_RGB = false;
  bool suppress_extra_bytes = false;
  bool repair_bb = false;
  bool repair_counters = false;
    bool edit_header = false;
    I32 set_file_source_ID = -1;
  bool set_file_source_ID_from_point_source_ID = false;
  I32 set_global_encoding = -1;
  I64 set_project_ID_GUID_data_1 = -1;
  I32 set_project_ID_GUID_data_2 = -1;
  I32 set_project_ID_GUID_data_3 = -1;
  I32 set_project_ID_GUID_data_4a = -1;
  I64 set_project_ID_GUID_data_4b = -1;
  I8 set_version_major = -1;
  I8 set_version_minor = -1;
	I8* set_system_identifier = 0;
	I8* set_generating_software = 0;
	I32 set_creation_day = -1;
	I32 set_creation_year = -1;
  U16 set_header_size = 0;
  U32 set_offset_to_point_data = 0;
  I32 set_number_of_variable_length_records = -1;
  I32 set_point_data_format = -1;
  I32 set_point_data_record_length = -1;
  I32 set_number_of_point_records = -1;
  I32 set_number_of_points_by_return[5] = {-1, -1, -1, -1, -1};
  F64* set_bounding_box = 0;
  F64* set_offset = 0;
  F64* set_scale = 0;
  I64 set_start_of_waveform_data_packet_record = -1;
  bool auto_date_creation = false;
  FILE* file_out = stderr;
  U32 horizontal_units = 0; 
  // extract a subsequence
  I64 subsequence_start = 0;
  I64 subsequence_stop = I64_MAX;
  U32 progress = 0;

  LAShistogram lashistogram;
  LASreadOpener lasreadopener;
  GeoProjectionConverter geoprojectionconverter;
  LASwriteOpener laswriteopener;

  if (argc == 1)
  {
#ifdef COMPILE_WITH_GUI
    return lasinfo_gui(argc, argv, 0);
#else
    fprintf(stderr,"%s is better run in the command line\n", argv[0]);
    char file_name[256];
    fprintf(stderr,"enter input file: "); fgets(file_name, 256, stdin);
    file_name[strlen(file_name)-1] = '\0';
    lasreadopener.set_file_name(file_name);
#endif
  }
  else
  {
    for (i = 1; i < argc; i++)
    {
        if (argv[i][0] == '') argv[i][0] = '-';
    }
    if (!lashistogram.parse(argc, argv)) byebye(true);
    if (!lasreadopener.parse(argc, argv)) byebye(true);
    if (!geoprojectionconverter.parse(argc, argv)) byebye(true);
    if (!laswriteopener.parse(argc, argv)) byebye(true);
  }

  if (laswriteopener.is_piped())
  {
    file_out = stdout;
  }

  for (i = 1; i < argc; i++)
  {
    if (argv[i][0] == '\0')
    {
      continue;
    }
    else if (strcmp(argv[i],"-h") == 0)
    {
      fprintf(stderr, "LAStools (by martin@rapidlasso.com) version %d\n", LAS_TOOLS_VERSION);
      usage();
    }
    else if (strcmp(argv[i],"-v") == 0)
    {
      verbose = true;
    }
    else if (strcmp(argv[i],"-version") == 0)
    {
      fprintf(stderr, "LAStools (by martin@rapidlasso.com) version %d\n", LAS_TOOLS_VERSION);
      byebye();
    }
    else if (strcmp(argv[i],"-wait") == 0)
    {
      wait = true;
    }
    else if (strcmp(argv[i],"-gui") == 0)
    {
#ifdef COMPILE_WITH_GUI
      gui = true;
#else
      fprintf(stderr, "WARNING: not compiled with GUI support. ignoring '-gui' ...\n");
#endif
    }
    else if (strcmp(argv[i],"-cores") == 0)
    {
#ifdef COMPILE_WITH_MULTI_CORE
      if ((i+1) >= argc)
      {
        fprintf(stderr,"ERROR: '%s' needs 1 argument: number\n", argv[i]);
        usage(true);
      }
      argv[i][0] = '\0';
      i++;
      cores = atoi(argv[i]);
      argv[i][0] = '\0';
#else
      fprintf(stderr, "WARNING: not compiled with multi-core batching. ignoring '-cores' ...\n");
      i++;
#endif
    }
    else if (strcmp(argv[i],"-cpu64") == 0)
    {
#ifdef COMPILE_WITH_MULTI_CORE
      cpu64 = TRUE;
#else
      fprintf(stderr, "WARNING: not compiled with 64 bit support. ignoring '-cpu64' ...\n");
#endif
      argv[i][0] = '\0';
    }
    else if (strcmp(argv[i],"-quiet") == 0)
    {
      file_out = 0;
    }
    else if (strcmp(argv[i],"-otxt") == 0)
    {
      laswriteopener.set_appendix("_info");
      laswriteopener.set_format("txt");
    }
    else if (strcmp(argv[i],"-nh") == 0 || strcmp(argv[i],"-no_header") == 0)
    {
      no_header = true;
    }
    else if (strcmp(argv[i],"-nv") == 0 || strcmp(argv[i],"-no_vlrs") == 0)
    {
      no_variable_header = true;
    }
    else if (strcmp(argv[i],"-nr") == 0 || strcmp(argv[i],"-no_returns") == 0)
    {
      no_returns = true;
    }
    else if (strcmp(argv[i],"-nmm") == 0 || strcmp(argv[i],"-no_min_max") == 0)
    {
      no_min_max = true;
    }
    else if (strcmp(argv[i],"-nw") == 0 || strcmp(argv[i],"-no_warnings") == 0)
    {
      no_warnings = true;
    }
    else if (strcmp(argv[i],"-nc") == 0 || strcmp(argv[i],"-no_check") == 0)
    {
      check_points = false;
    }
    else if (strcmp(argv[i],"-cd") == 0 || strcmp(argv[i],"-compute_density") == 0)
    {
      compute_density = true;
    }
    else if (strcmp(argv[i],"-gw") == 0 || strcmp(argv[i],"-gps_week") == 0)
    {
      gps_week = true;
    }
    else if (strcmp(argv[i],"-nco") == 0 || strcmp(argv[i],"-no_check_outside") == 0)
    {
      check_outside = false;
    }
    else if (strcmp(argv[i],"-ro") == 0 || strcmp(argv[i],"-report_outside") == 0)
    {
      report_outside = true;
      check_outside = true;
    }
    else if (strcmp(argv[i],"-subseq") == 0)
    {
      if ((i+2) >= argc)
      {
        fprintf(stderr,"ERROR: '%s' needs 2 arguments: start stop\n", argv[i]);
        byebye(true);
      }
#ifdef _WIN32
      if (sscanf(argv[i+1], "%I64d", &subsequence_start) != 1)
#else
      if (sscanf(argv[i+1], "%lld", &subsequence_start) != 1)
#endif
      {
        fprintf(stderr,"ERROR: '%s' needs 2 arguments: start stop but '%s' is not a valid start\n", argv[i], argv[i+1]);
        byebye(true);
      }
      if (subsequence_start < 0)
      {
#ifdef _WIN32
        fprintf(stderr,"ERROR: '%s' needs 2 arguments: start stop but '%I64d' is not a valid start\n", argv[i], subsequence_start);
#else
        fprintf(stderr,"ERROR: '%s' needs 2 arguments: start stop but '%lld' is not a valid start\n", argv[i], subsequence_start);
#endif
        byebye(true);
      }
#ifdef _WIN32
      if (sscanf(argv[i+2], "%I64d", &subsequence_stop) != 1)
#else
      if (sscanf(argv[i+2], "%lld", &subsequence_stop) != 1)
#endif
      {
        fprintf(stderr,"ERROR: '%s' needs 2 arguments: start stop but '%s' is not a valid stop\n", argv[i], argv[i+2]);
        byebye(true);
      }
      if (subsequence_stop < 0)
      {
#ifdef _WIN32
        fprintf(stderr,"ERROR: '%s' needs 2 arguments: start stop but '%I64d' is not a valid stop\n", argv[i], subsequence_stop);
#else
        fprintf(stderr,"ERROR: '%s' needs 2 arguments: start stop but '%lld' is not a valid stop\n", argv[i], subsequence_stop);
#endif
        byebye(true);
      }
      if (subsequence_start >= subsequence_stop)
      {
#ifdef _WIN32
        fprintf(stderr,"ERROR: '%s' needs 2 arguments: start stop but '%I64d' and '%I64d' are no valid start and stop combination \n", argv[i], subsequence_start, subsequence_stop);
#else
        fprintf(stderr,"ERROR: '%s' needs 2 arguments: start stop but '%lld' and '%lld' are no valid start and stop combination \n", argv[i], subsequence_start, subsequence_stop);
#endif
        byebye(true);
      }
      i+=2;
    }
    else if (strcmp(argv[i],"-start_at_point") == 0)
    {
      if ((i+1) >= argc)
      {
        fprintf(stderr,"ERROR: '%s' needs 1 argument: start\n", argv[i]);
        byebye(true);
      }
#ifdef _WIN32
      if (sscanf(argv[i+1], "%I64d", &subsequence_start) != 1)
#else
      if (sscanf(argv[i+1], "%lld", &subsequence_start) != 1)
#endif
      {
        fprintf(stderr,"ERROR: '%s' needs 1 argument: start but '%s' is not a valid start\n", argv[i], argv[i+1]);
        byebye(true);
      }
      if (subsequence_start < 0)
      {
#ifdef _WIN32
        fprintf(stderr,"ERROR: '%s' needs 1 argument: start but '%I64d' is not a valid start\n", argv[i], subsequence_start);
#else
        fprintf(stderr,"ERROR: '%s' needs 1 argument: start but '%lld' is not a valid start\n", argv[i], subsequence_start);
#endif
        byebye(true);
      }
      i+=1;
    }
    else if (strcmp(argv[i],"-stop_at_point") == 0)
    {
      if ((i+1) >= argc)
      {
        fprintf(stderr,"ERROR: '%s' needs 1 argument: stop\n", argv[i]);
        byebye(true);
      }
#ifdef _WIN32
      if (sscanf(argv[i+1], "%I64d", &subsequence_stop) != 1)
#else
      if (sscanf(argv[i+1], "%lld", &subsequence_stop) != 1)
#endif
      {
        fprintf(stderr,"ERROR: '%s' needs 1 argument: start but '%s' is not a valid stop\n", argv[i], argv[i+1]);
        byebye(true);
      }
      if (subsequence_stop < 0)
      {
#ifdef _WIN32
        fprintf(stderr,"ERROR: '%s' needs 1 argument: start but '%I64d' is not a valid stop\n", argv[i], subsequence_stop);
#else
        fprintf(stderr,"ERROR: '%s' needs 1 argument: start but '%lld' is not a valid stop\n", argv[i], subsequence_stop);
#endif
        byebye(true);
      }
      i+=1;
    } else if (strcmp(argv[i], "-repair") == 0) {
        repair_bb = true;
        repair_counters = true;
    } else if (strcmp(argv[i], "-repair_bb") == 0) {
        repair_bb = true;
    } else if (strcmp(argv[i], "-repair_counters") == 0) {
        repair_counters = true;
    }
    else if (strcmp(argv[i],"-auto_date") == 0 || strcmp(argv[i],"-auto_creation_date") == 0 || strcmp(argv[i],"-auto_creation") == 0)
    {
      auto_date_creation = true;
    } else if (strcmp(argv[i], "-set_file_source_ID") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: index\n", argv[i]);
            byebye(true);
        }
        i++;
        set_file_source_ID = atoi(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_file_source_ID_from_point_source_ID") == 0) {
        set_file_source_ID_from_point_source_ID = true;
        edit_header = true;
    } else if (strcmp(argv[i], "-set_GUID") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: value1\n", argv[i]);
            byebye(true);
        }
        i++;
#ifdef _WIN32
        if (sscanf(argv[i], "%I64x-%x-%x-%x-%I64x", &set_project_ID_GUID_data_1, &set_project_ID_GUID_data_2, &set_project_ID_GUID_data_3, &set_project_ID_GUID_data_4a, &set_project_ID_GUID_data_4b) != 5)
#else
        if (sscanf(argv[i], "%llx-%x-%x-%x-%llx", &set_project_ID_GUID_data_1, &set_project_ID_GUID_data_2,
                   &set_project_ID_GUID_data_3, &set_project_ID_GUID_data_4a, &set_project_ID_GUID_data_4b) != 5)
#endif
        {
            if ((i + 1) >= argc) {
                fprintf(stderr, "ERROR: '%s' needs hexadecimal GUID in 'F794F8A4-A23E-421E-A134-ACF7754E1C54' format\n",
                        argv[i]);
                byebye(true);
            }
        }
        edit_header = true;
    } else if (strcmp(argv[i], "-set_system_identifier") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: name\n", argv[i]);
            byebye(true);
        }
        i++;
        set_system_identifier = new I8[32];
        memset(set_system_identifier, 0, 32);
        strncpy(set_system_identifier, argv[i], 32);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_generating_software") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: name\n", argv[i]);
            byebye(true);
        }
        i++;
        set_generating_software = new I8[32];
        memset(set_generating_software, 0, 32);
        strncpy(set_generating_software, argv[i], 32);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_bb") == 0 || strcmp(argv[i], "-set_bounding_box") == 0) {
        if ((i + 6) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 6 arguments: min_x min_y min_z max_x max_y max_z\n", argv[i]);
            byebye(true);
        }
        set_bounding_box = new F64[6];
        i++;
        set_bounding_box[1] = atof(argv[i]);
        i++;
        set_bounding_box[3] = atof(argv[i]);
        i++;
        set_bounding_box[5] = atof(argv[i]);
        i++;
        set_bounding_box[0] = atof(argv[i]);
        i++;
        set_bounding_box[2] = atof(argv[i]);
        i++;
        set_bounding_box[4] = atof(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_offset") == 0) {
        if ((i + 3) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 3 arguments: x y z\n", argv[i]);
            byebye(true);
        }
        set_offset = new F64[3];
        i++;
        set_offset[0] = atof(argv[i]);
        i++;
        set_offset[1] = atof(argv[i]);
        i++;
        set_offset[2] = atof(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_scale") == 0) {
        if ((i + 3) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 3 arguments: x y z\n", argv[i]);
            byebye(true);
        }
        set_scale = new F64[3];
        i++;
        set_scale[0] = atof(argv[i]);
        i++;
        set_scale[1] = atof(argv[i]);
        i++;
        set_scale[2] = atof(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_global_encoding") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: number\n", argv[i]);
            byebye(true);
        }
        i++;
        set_global_encoding = atoi(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_version") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: major.minor\n", argv[i]);
            byebye(true);
        }
        i++;
        int major;
        int minor;
        if (sscanf(argv[i], "%d.%d", &major, &minor) != 2) {
            fprintf(stderr, "ERROR: cannot understand argument '%s' of '%s'\n", argv[i], argv[i - 1]);
            usage();
        }
        set_version_major = (I8) major;
        set_version_minor = (I8) minor;
        edit_header = true;
    } else if (strcmp(argv[i], "-set_creation_date") == 0 || strcmp(argv[i], "-set_file_creation") == 0) {
        if ((i + 2) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 2 arguments: day year\n", argv[i]);
            byebye(true);
        }
        i++;
        set_creation_day = (U16) atoi(argv[i]);
        i++;
        set_creation_year = (U16) atoi(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_number_of_point_records") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: number\n", argv[i]);
            byebye(true);
        }
        i++;
        set_number_of_point_records = atoi(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_number_of_points_by_return") == 0) {
        if ((i + 5) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 5 arguments: ret1 ret2 ret3 ret4 ret5\n", argv[i]);
            byebye(true);
        }
        i++;
        set_number_of_points_by_return[0] = atoi(argv[i]);
        i++;
        set_number_of_points_by_return[1] = atoi(argv[i]);
        i++;
        set_number_of_points_by_return[2] = atoi(argv[i]);
        i++;
        set_number_of_points_by_return[3] = atoi(argv[i]);
        i++;
        set_number_of_points_by_return[4] = atoi(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_header_size") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: size\n", argv[i]);
            byebye(true);
        }
        i++;
        set_header_size = atoi(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_offset_to_point_data") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: offset\n", argv[i]);
            byebye(true);
        }
        i++;
        set_offset_to_point_data = atoi(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_number_of_variable_length_records") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: number\n", argv[i]);
            byebye(true);
        }
        i++;
        set_number_of_variable_length_records = atoi(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_point_data_format") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: type\n", argv[i]);
            byebye(true);
        }
        i++;
        set_point_data_format = atoi(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_point_data_record_length") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: size\n", argv[i]);
            byebye(true);
        }
        i++;
        set_point_data_record_length = atoi(argv[i]);
        edit_header = true;
    } else if (strcmp(argv[i], "-set_start_of_waveform_data_packet_record") == 0) {
        if ((i + 1) >= argc) {
            fprintf(stderr, "ERROR: '%s' needs 1 argument: start\n", argv[i]);
            byebye(true);
        }
        i++;
        set_start_of_waveform_data_packet_record = atoi(argv[i]);
        edit_header = true;
    } else if ((strncmp(argv[i], "-suppress_", 10) == 0))
    {
      if (strcmp(argv[i],"-suppress_z") == 0)
      {
        suppress_z = true;
      }
      else if (strcmp(argv[i],"-suppress_classification") == 0)
      {
        suppress_classification = true;
      }
      else if (strcmp(argv[i],"-suppress_flags") == 0)
      {
        suppress_flags = true;
      }
      else if (strcmp(argv[i],"-suppress_intensity") == 0)
      {
        suppress_intensity = true;
      }
      else if (strcmp(argv[i],"-suppress_user_data") == 0)
      {
        suppress_user_data = true;
      }
      else if (strcmp(argv[i],"-suppress_point_source") == 0)
      {
        suppress_point_source = true;
      }
      else if (strcmp(argv[i],"-suppress_scan_angle") == 0)
      {
        suppress_scan_angle = true;
      }
      else if (strcmp(argv[i],"-suppress_RGB") == 0)
      {
        suppress_RGB = true;
      }
      else if (strcmp(argv[i],"-suppress_extra_bytes") == 0)
      {
        suppress_extra_bytes = true;
      }
      else
      {
        fprintf(stderr, "ERROR: cannot understand argument '%s'\n", argv[i]);
        byebye(TRUE);
      }
    }
    else if (strcmp(argv[i],"-progress") == 0)
    {
      if ((i+1) >= argc)
      {
        fprintf(stderr,"ERROR: '%s' needs 1 argument: every\n", argv[i]);
        byebye(true);
      }
			i++;
        progress = atoi(argv[i]);
    }
    else if ((argv[i][0] != '-') && (lasreadopener.get_file_name_number() == 0))
    {
      lasreadopener.add_file_name(argv[i]);
      argv[i][0] = '\0';
    }
    else
    {
      fprintf(stderr, "ERROR: cannot understand argument '%s'\n", argv[i]);
      byebye(true);
    }
  }

#ifdef COMPILE_WITH_GUI
  if (gui)
  {
    return lasinfo_gui(argc, argv, &lasreadopener);
  }
#endif

#ifdef COMPILE_WITH_MULTI_CORE
  if (cores > 1)
  {
    if (lasreadopener.get_file_name_number() < 2)
    {
      fprintf(stderr,"WARNING: only %u input files. ignoring '-cores %d' ...\n", lasreadopener.get_file_name_number(), cores);
    }
    else if (lasreadopener.is_merged())
    {
      fprintf(stderr,"WARNING: input files merged on-the-fly. ignoring '-cores %d' ...\n", cores);
    }
    else
    {
      return lasinfo_multi_core(argc, argv, &lasreadopener, &lashistogram, &laswriteopener, cores, cpu64);
    }
  }
  if (cpu64)
  {
    return lasinfo_multi_core(argc, argv, &lasreadopener, &lashistogram, &laswriteopener, 1, TRUE);
  }
#endif

  // check input

  if (!lasreadopener.active())
  {
    fprintf (stderr, "ERROR: no input specified\n");
    byebye(true, argc==1);
  }

  // omit "suppressed" layers from LAZ decompression (for new LAS 1.4 point types only)

  U32 decompress_selective = LASZIP_DECOMPRESS_SELECTIVE_ALL;

  if (suppress_z)
  {
    decompress_selective &= ~LASZIP_DECOMPRESS_SELECTIVE_Z;
  }

  if (suppress_classification)
  {
    decompress_selective &= ~LASZIP_DECOMPRESS_SELECTIVE_CLASSIFICATION;
  }

  if (suppress_flags)
  {
    decompress_selective &= ~LASZIP_DECOMPRESS_SELECTIVE_FLAGS;
  }
  
  if (suppress_intensity)
  {
    decompress_selective &= ~LASZIP_DECOMPRESS_SELECTIVE_INTENSITY;
  }

  if (suppress_user_data)
  {
    decompress_selective &= ~LASZIP_DECOMPRESS_SELECTIVE_USER_DATA;
  }

  if (suppress_point_source)
  {
    decompress_selective &= ~LASZIP_DECOMPRESS_SELECTIVE_POINT_SOURCE;
  }

  if (suppress_scan_angle)
  {
    decompress_selective &= ~LASZIP_DECOMPRESS_SELECTIVE_SCAN_ANGLE;
  }
  
  if (suppress_RGB)
  {
    decompress_selective &= ~LASZIP_DECOMPRESS_SELECTIVE_RGB;
  }

  if (suppress_extra_bytes)
  {
    decompress_selective &= ~LASZIP_DECOMPRESS_SELECTIVE_EXTRA_BYTES;
  }
  
  lasreadopener.set_decompress_selective(decompress_selective);

  // possibly loop over multiple input files

  while (lasreadopener.active())
  {
    if (edit_header)
    {
      if (lasreadopener.is_piped())
      {
        fprintf(stderr, "ERROR: cannot edit header of piped input\n");
        edit_header = false;
      }
      else if (lasreadopener.is_merged())
      {
        fprintf(stderr, "ERROR: cannot edit header of merged input\n");
        edit_header = false;
      }
      else if (lasreadopener.is_buffered())
      {
        fprintf(stderr, "ERROR: cannot edit header of buffered input\n");
        edit_header = false;
      }
      const CHAR* file_name = lasreadopener.get_file_name(lasreadopener.get_file_name_current());
      if ((strstr(file_name, ".laz") == 0) && (strstr(file_name, ".las") == 0) && (strstr(file_name, ".LAZ") == 0) && (strstr(file_name, ".LAS") == 0))
      {
        fprintf(stderr, "ERROR: can only edit for LAS or LAZ files, not for '%s'\n", file_name);
        edit_header = false;
      }
      if (set_file_source_ID_from_point_source_ID)
      {
        LASreader* lasreader = lasreadopener.open(file_name, FALSE);
        if (lasreader == 0)
        {
          fprintf(stderr, "ERROR: cannot open lasreader for '%s'\n", file_name);
          byebye(true, argc==1);
        }
        if (lasreader->read_point())
        {
          set_file_source_ID = lasreader->point.get_point_source_ID();
        }
        else
        {
          set_file_source_ID = -1;
        }
        lasreader->close();
        delete lasreader;
      }
      FILE* file = fopen(file_name, "rb+");
      if (file == 0)
      {
        fprintf (stderr, "ERROR: could not open file '%s' for edit of header\n", file_name);
        edit_header = false;
      }
      else if (edit_header)
      {
        if (set_file_source_ID != -1)
        {
          U16 file_source_ID = U16_CLAMP(set_file_source_ID);
          fseek(file, 4, SEEK_SET);
          fwrite(&file_source_ID, sizeof(U16), 1, file);
        }
        if (set_global_encoding != -1)
        {
          U16 global_encoding = U16_CLAMP(set_global_encoding);
          fseek(file, 6, SEEK_SET);
          fwrite(&global_encoding, sizeof(U16), 1, file);
        }
        if (set_project_ID_GUID_data_1 != -1)
        {
          fseek(file, 8, SEEK_SET);
          U32 GUID_data_1 = U32_CLAMP(set_project_ID_GUID_data_1);
          U16 GUID_data_2 = U16_CLAMP(set_project_ID_GUID_data_2);
          U16 GUID_data_3 = U16_CLAMP(set_project_ID_GUID_data_3);
          U16 GUID_data_4a = U16_CLAMP(set_project_ID_GUID_data_4a);
          U16 GUID_data_4b_a = U16_CLAMP(set_project_ID_GUID_data_4b >> 32);
          U32 GUID_data_4b_b = U32_CLAMP(set_project_ID_GUID_data_4b & 0xFFFFFFFF);
          fwrite(&GUID_data_1, sizeof(U32), 1, file);
          fwrite(&GUID_data_2, sizeof(U16), 1, file);
          fwrite(&GUID_data_3, sizeof(U16), 1, file);
          fwrite(&GUID_data_4a, sizeof(U16), 1, file);
          fwrite(&GUID_data_4b_a, sizeof(U16), 1, file);
          fwrite(&GUID_data_4b_b, sizeof(U32), 1, file);
        }
        if (set_version_major != -1)
        {
          fseek(file, 24, SEEK_SET);
          fwrite(&set_version_major, sizeof(I8), 1, file);
        }
        if (set_version_minor != -1)
        {
          fseek(file, 25, SEEK_SET);
          fwrite(&set_version_minor, sizeof(I8), 1, file);
        }
        if (set_system_identifier)
        {
          fseek(file, 26, SEEK_SET);
          fwrite(set_system_identifier, sizeof(I8), 32, file);
        }
        if (set_generating_software)
        {
          fseek(file, 58, SEEK_SET);
          fwrite(set_generating_software, sizeof(I8), 32, file);
        }
        if (set_creation_day != -1)
        {
          U16 creation_day = U16_CLAMP(set_creation_day);
          fseek(file, 90, SEEK_SET);
          fwrite(&creation_day, sizeof(U16), 1, file);
        }
        if (set_creation_year != -1)
        {
          U16 creation_year = U16_CLAMP(set_creation_year);
          fseek(file, 92, SEEK_SET);
          fwrite(&creation_year, sizeof(U16), 1, file);
        }
        if (set_header_size)
        {
          fseek(file, 94, SEEK_SET);
          fwrite(&set_header_size, sizeof(U16), 1, file);
        }
        if (set_offset_to_point_data)
        {
          fseek(file, 96, SEEK_SET);
          fwrite(&set_offset_to_point_data, sizeof(U32), 1, file);
        }
        if (set_number_of_variable_length_records != -1)
        {
          fseek(file, 100, SEEK_SET);
          fwrite(&set_number_of_variable_length_records, sizeof(U32), 1, file);
        }
        if (set_point_data_format != -1)
        {
          U8 point_data_format = U8_CLAMP(set_point_data_format);
          fseek(file, 104, SEEK_SET);
          fwrite(&point_data_format, sizeof(U8), 1, file);
        }
        if (set_point_data_record_length != -1)
        {
          U16 point_data_record_length = U16_CLAMP(set_point_data_record_length);
          fseek(file, 105, SEEK_SET);
          fwrite(&point_data_record_length, sizeof(U16), 1, file);
        }
        if (set_number_of_point_records != -1)
        {
          fseek(file, 107, SEEK_SET);
          fwrite(&set_number_of_point_records, sizeof(I32), 1, file);
        }
        if (set_number_of_points_by_return[0] != -1)
        {
          fseek(file, 111, SEEK_SET);
          fwrite(&(set_number_of_points_by_return[0]), sizeof(I32), 1, file);
        }
        if (set_number_of_points_by_return[1] != -1)
        {
          fseek(file, 115, SEEK_SET);
          fwrite(&(set_number_of_points_by_return[1]), sizeof(I32), 1, file);
        }
        if (set_number_of_points_by_return[2] != -1)
        {
          fseek(file, 119, SEEK_SET);
          fwrite(&(set_number_of_points_by_return[2]), sizeof(I32), 1, file);
        }
        if (set_number_of_points_by_return[3] != -1)
        {
          fseek(file, 123, SEEK_SET);
          fwrite(&(set_number_of_points_by_return[3]), sizeof(I32), 1, file);
        }
        if (set_number_of_points_by_return[4] != -1)
        {
          fseek(file, 127, SEEK_SET);
          fwrite(&(set_number_of_points_by_return[4]), sizeof(I32), 1, file);
        }
        if (set_scale)
        {
          fseek(file, 131, SEEK_SET);
          fwrite(set_scale, 3*sizeof(F64), 1, file);
        }
        if (set_offset)
        {
          fseek(file, 155, SEEK_SET);
          fwrite(set_offset, 3*sizeof(F64), 1, file);
        }
        if (set_bounding_box)
        {
          fseek(file, 179, SEEK_SET);
          fwrite(set_bounding_box, 6*sizeof(F64), 1, file);
        }
        if (set_start_of_waveform_data_packet_record != -1)
        {
          fseek(file, 227, SEEK_SET);
          fwrite(&set_start_of_waveform_data_packet_record, sizeof(I64), 1, file);
        }
        if (verbose) fprintf(stderr, "edited '%s' ...\n", file_name);
        fclose(file);
      }
    }

    // open lasreader

    LASreader* lasreader = lasreadopener.open();
    if (lasreader == 0)
    {
      fprintf(stderr, "ERROR: cannot open lasreader\n");
      byebye(true, argc==1);
    }

    LASheader* lasheader = &lasreader->header;

#ifdef _WIN32
    if (verbose) fprintf(stderr, "%s '%s' with %I64d points\n", (repair_bb || repair_counters ? "repairing" : "reading"), (lasreadopener.get_file_name() ? lasreadopener.get_file_name() : "stdin"), lasreader->npoints);
#else
    if (verbose) fprintf(stderr, "%s '%s' with %lld points\n", (repair_bb || repair_counters ? "repairing" : "reading"), (lasreadopener.get_file_name() ? lasreadopener.get_file_name() : "stdin"), lasreader->npoints);
#endif

    if (auto_date_creation && lasreadopener.get_file_name())
    {
#ifdef _WIN32
      WIN32_FILE_ATTRIBUTE_DATA attr;
	    SYSTEMTIME creation;
      GetFileAttributesEx(lasreadopener.get_file_name(), GetFileExInfoStandard, &attr);
	    FileTimeToSystemTime(&attr.ftCreationTime, &creation);
      int startday[13] = {-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
      set_creation_day = startday[creation.wMonth] + creation.wDay;
      set_creation_year = creation.wYear;
      // leap year handling
      if ((((creation.wYear)%4) == 0) && (creation.wMonth > 2)) set_creation_day++;
      edit_header = true;
#endif
    }

    if (laswriteopener.get_file_name() == 0)
    {
      if (lasreadopener.get_file_name() && (laswriteopener.get_format() == LAS_TOOLS_FORMAT_TXT))
      {
        laswriteopener.make_file_name(lasreadopener.get_file_name(), -2);
      }
    }

    if (laswriteopener.get_file_name())
    {
      // make sure we do not corrupt the input file
      if (lasreadopener.get_file_name() && (strcmp(lasreadopener.get_file_name(), laswriteopener.get_file_name()) == 0))
      {
        fprintf(stderr, "ERROR: input and output file name for '%s' are identical\n", lasreadopener.get_file_name());
        usage(true);
      }
      // open the text output file
      file_out = fopen(laswriteopener.get_file_name(), "w");
      if (file_out == 0)
      {
        fprintf (stderr, "WARNING: could not open output text file '%s'\n", laswriteopener.get_file_name());
        file_out = stderr;
      }
    }

    // print name of input

    if (file_out)
    {
      if (lasreadopener.is_merged())
      {
        fprintf(file_out, "lasinfo (%u) report for %u merged files\012", LAS_TOOLS_VERSION, lasreadopener.get_file_name_number());
      }
      else if (lasreadopener.is_piped())
      {
        fprintf(file_out, "lasinfo (%u) report for piped input\012", LAS_TOOLS_VERSION);
      }
      else if (lasreadopener.get_file_name())
      {
        fprintf(file_out, "lasinfo (%u) report for '%s'\012", LAS_TOOLS_VERSION, lasreadopener.get_file_name());
      }
    }

    U32 number_of_point_records = lasheader->number_of_point_records;
    U32 number_of_points_by_return0 = lasheader->number_of_points_by_return[0];

    // print header info

    CHAR printstring[4096];

    if (file_out && !no_header)
    {
      if (lasreadopener.is_merged() && (lasreader->header.version_minor < 4))
      {
#ifdef _WIN32
        if (lasreader->npoints > number_of_point_records) fprintf(file_out, "WARNING: merged file has %I64d points, more than the 32 bits counters of LAS 1.%d can handle.\012", lasreader->npoints, lasreader->header.version_minor);
#else
        if (lasreader->npoints > number_of_point_records) fprintf(file_out, "WARNING: merged file has %lld points, more than the 32 bits counters of LAS 1.%d can handle.\012", lasreader->npoints, lasreader->header.version_minor);
#endif
      }
      fprintf(file_out, "reporting all LAS header entries:\012");
      fprintf(file_out, "  file signature:             '%.4s'\012", lasheader->file_signature);
      fprintf(file_out, "  file source ID:             %d\012", lasheader->file_source_ID);
      fprintf(file_out, "  global_encoding:            %d\012", lasheader->global_encoding);
      fprintf(file_out, "  project ID GUID data 1-4:   %08X-%04X-%04X-%04X-%04X%08X\012", lasheader->project_ID_GUID_data_1, lasheader->project_ID_GUID_data_2, lasheader->project_ID_GUID_data_3, *((U16*)(lasheader->project_ID_GUID_data_4)), *((U16*)(lasheader->project_ID_GUID_data_4+2)), *((U32*)(lasheader->project_ID_GUID_data_4+4)));
      fprintf(file_out, "  version major.minor:        %d.%d\012", lasheader->version_major, lasheader->version_minor);
      fprintf(file_out, "  system identifier:          '%.32s'\012", lasheader->system_identifier);
      fprintf(file_out, "  generating software:        '%.32s'\012", lasheader->generating_software);
      fprintf(file_out, "  file creation day/year:     %d/%d\012", lasheader->file_creation_day, lasheader->file_creation_year);
      fprintf(file_out, "  header size:                %d\012", lasheader->header_size);
      fprintf(file_out, "  offset to point data:       %u\012", lasheader->offset_to_point_data);
      fprintf(file_out, "  number var. length records: %u\012", lasheader->number_of_variable_length_records);
      fprintf(file_out, "  point data format:          %d\012", lasheader->point_data_format);
      fprintf(file_out, "  point data record length:   %d\012", lasheader->point_data_record_length);
      fprintf(file_out, "  number of point records:    %u\012", lasheader->number_of_point_records);
      fprintf(file_out, "  number of points by return: %u %u %u %u %u\012", lasheader->number_of_points_by_return[0], lasheader->number_of_points_by_return[1], lasheader->number_of_points_by_return[2], lasheader->number_of_points_by_return[3], lasheader->number_of_points_by_return[4]);
      fprintf(file_out, "  scale factor x y z:         "); lidardouble2string(printstring, lasheader->x_scale_factor); fprintf(file_out, "%s ", printstring);  lidardouble2string(printstring, lasheader->y_scale_factor); fprintf(file_out, "%s ", printstring);  lidardouble2string(printstring, lasheader->z_scale_factor); fprintf(file_out, "%s\012", printstring);
      fprintf(file_out, "  offset x y z:               "); lidardouble2string(printstring, lasheader->x_offset); fprintf(file_out, "%s ", printstring);  lidardouble2string(printstring, lasheader->y_offset); fprintf(file_out, "%s ", printstring);  lidardouble2string(printstring, lasheader->z_offset); fprintf(file_out, "%s\012", printstring);
      fprintf(file_out, "  min x y z:                  "); lidardouble2string(printstring, lasheader->min_x, lasheader->x_scale_factor); fprintf(file_out, "%s ", printstring); lidardouble2string(printstring, lasheader->min_y, lasheader->y_scale_factor); fprintf(file_out, "%s ", printstring); lidardouble2string(printstring, lasheader->min_z, lasheader->z_scale_factor); fprintf(file_out, "%s\012", printstring);
      fprintf(file_out, "  max x y z:                  "); lidardouble2string(printstring, lasheader->max_x, lasheader->x_scale_factor); fprintf(file_out, "%s ", printstring); lidardouble2string(printstring, lasheader->max_y, lasheader->y_scale_factor); fprintf(file_out, "%s ", printstring); lidardouble2string(printstring, lasheader->max_z, lasheader->z_scale_factor); fprintf(file_out, "%s\012", printstring);
      if (!no_warnings && !valid_resolution(lasheader->min_x, lasheader->x_offset, lasheader->x_scale_factor))
      {
        fprintf(file_out, "WARNING: stored resolution of min_x not compatible with x_offset and x_scale_factor: "); lidardouble2string(printstring, lasheader->min_x); fprintf(file_out, "%s\n", printstring);
      }
      if (!no_warnings && !valid_resolution(lasheader->min_y, lasheader->y_offset, lasheader->y_scale_factor))
      {
        fprintf(file_out, "WARNING: stored resolution of min_y not compatible with y_offset and y_scale_factor: "); lidardouble2string(printstring, lasheader->min_y); fprintf(file_out, "%s\n", printstring);
      }
      if (!no_warnings && !valid_resolution(lasheader->min_z, lasheader->z_offset, lasheader->z_scale_factor))
      {
        fprintf(file_out, "WARNING: stored resolution of min_z not compatible with z_offset and z_scale_factor: "); lidardouble2string(printstring, lasheader->min_z); fprintf(file_out, "%s\n", printstring);
      }
      if (!no_warnings && !valid_resolution(lasheader->max_x, lasheader->x_offset, lasheader->x_scale_factor))
      {
        fprintf(file_out, "WARNING: stored resolution of max_x not compatible with x_offset and x_scale_factor: "); lidardouble2string(printstring, lasheader->max_x); fprintf(file_out, "%s\n", printstring);
      }
      if (!no_warnings && !valid_resolution(lasheader->max_y, lasheader->y_offset, lasheader->y_scale_factor))
      {
        fprintf(file_out, "WARNING: stored resolution of max_y not compatible with y_offset and y_scale_factor: "); lidardouble2string(printstring, lasheader->max_y); fprintf(file_out, "%s\n", printstring);
      }
      if (!no_warnings && !valid_resolution(lasheader->max_z, lasheader->z_offset, lasheader->z_scale_factor))
      {
        fprintf(file_out, "WARNING: stored resolution of max_z not compatible with z_offset and z_scale_factor: "); lidardouble2string(printstring, lasheader->max_z); fprintf(file_out, "%s\n", printstring);
      }
      if ((lasheader->version_major == 1) && (lasheader->version_minor >= 3))
      {
#ifdef _WIN32
        fprintf(file_out, "  start of waveform data packet record: %I64d\012", lasheader->start_of_waveform_data_packet_record);
#else
        fprintf(file_out, "  start of waveform data packet record: %lld\012", lasheader->start_of_waveform_data_packet_record);
#endif
      }
      if ((lasheader->version_major == 1) && (lasheader->version_minor >= 4))
      {
#ifdef _WIN32
        fprintf(file_out, "  start of first extended variable length record: %I64d\012", lasheader->start_of_first_extended_variable_length_record);
#else
        fprintf(file_out, "  start of first extended variable length record: %lld\012", lasheader->start_of_first_extended_variable_length_record);
#endif
        fprintf(file_out, "  number of extended_variable length records: %d\012", lasheader->number_of_extended_variable_length_records);
#ifdef _WIN32
        fprintf(file_out, "  extended number of point records: %I64d\012", lasheader->extended_number_of_point_records);
        fprintf(file_out, "  extended number of points by return: %I64d %I64d %I64d %I64d %I64d %I64d %I64d %I64d %I64d %I64d %I64d %I64d %I64d %I64d %I64d\012", lasheader->extended_number_of_points_by_return[0], lasheader->extended_number_of_points_by_return[1], lasheader->extended_number_of_points_by_return[2], lasheader->extended_number_of_points_by_return[3], lasheader->extended_number_of_points_by_return[4], lasheader->extended_number_of_points_by_return[5], lasheader->extended_number_of_points_by_return[6], lasheader->extended_number_of_points_by_return[7], lasheader->extended_number_of_points_by_return[8], lasheader->extended_number_of_points_by_return[9], lasheader->extended_number_of_points_by_return[10], lasheader->extended_number_of_points_by_return[11], lasheader->extended_number_of_points_by_return[12], lasheader->extended_number_of_points_by_return[13], lasheader->extended_number_of_points_by_return[14]);
#else
        fprintf(file_out, "  extended number of point records: %lld\012", lasheader->extended_number_of_point_records);
        fprintf(file_out, "  extended number of points by return: %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld\012", lasheader->extended_number_of_points_by_return[0], lasheader->extended_number_of_points_by_return[1], lasheader->extended_number_of_points_by_return[2], lasheader->extended_number_of_points_by_return[3], lasheader->extended_number_of_points_by_return[4], lasheader->extended_number_of_points_by_return[5], lasheader->extended_number_of_points_by_return[6], lasheader->extended_number_of_points_by_return[7], lasheader->extended_number_of_points_by_return[8], lasheader->extended_number_of_points_by_return[9], lasheader->extended_number_of_points_by_return[10], lasheader->extended_number_of_points_by_return[11], lasheader->extended_number_of_points_by_return[12], lasheader->extended_number_of_points_by_return[13], lasheader->extended_number_of_points_by_return[14]);
#endif
      }
      if (lasheader->user_data_in_header_size) fprintf(file_out, "the header contains %u user-defined bytes\012", lasheader->user_data_in_header_size);
    }

    // maybe print variable header

    if (file_out && !no_variable_header)
    {
      for (int i = 0; i < (int)lasheader->number_of_variable_length_records; i++)
      {
        fprintf(file_out, "variable length header record %d of %d:\012", i+1, (int)lasheader->number_of_variable_length_records);
        fprintf(file_out, "  reserved             %d\012", lasreader->header.vlrs[i].reserved);
          fprintf(file_out, "  user ID              '%s'\012", lasreader->header.vlrs[i].user_id);
        fprintf(file_out, "  record ID            %d\012", lasreader->header.vlrs[i].record_id);
        fprintf(file_out, "  length after header  %d\012", lasreader->header.vlrs[i].record_length_after_header);
          fprintf(file_out, "  description          '%s'\012", lasreader->header.vlrs[i].description);

        // special handling for known variable header tags

        if ((strcmp(lasheader->vlrs[i].user_id, "LASF_Projection") == 0) && (lasheader->vlrs[i].data != 0))
        {
          if (lasheader->vlrs[i].record_id == 34735) // GeoKeyDirectoryTag
          {
            fprintf(file_out, "    GeoKeyDirectoryTag version %d.%d.%d number of keys %d\012", lasheader->vlr_geo_keys->key_directory_version, lasheader->vlr_geo_keys->key_revision, lasheader->vlr_geo_keys->minor_revision, lasheader->vlr_geo_keys->number_of_keys);
            for (int j = 0; j < lasheader->vlr_geo_keys->number_of_keys; j++)
            {
              if (file_out)
              {
                fprintf(file_out, "      key %d tiff_tag_location %d count %d value_offset %d - ", lasheader->vlr_geo_key_entries[j].key_id, lasheader->vlr_geo_key_entries[j].tiff_tag_location, lasheader->vlr_geo_key_entries[j].count, lasheader->vlr_geo_key_entries[j].value_offset);
                switch (lasreader->header.vlr_geo_key_entries[j].key_id)
                {
                case 1024: // GTModelTypeGeoKey 
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 1: // ModelTypeProjected   
                    fprintf(file_out, "GTModelTypeGeoKey: ModelTypeProjected\012");
                    break;
                  case 2:
                    fprintf(file_out, "GTModelTypeGeoKey: ModelTypeGeographic\012");
                    break;
                  case 3:
                    fprintf(file_out, "GTModelTypeGeoKey: ModelTypeGeocentric\012");
                    break;
                  case 0: // ModelTypeUndefined   
                    fprintf(file_out, "GTModelTypeGeoKey: ModelTypeUndefined\012");
                    break;
                  default:
                    fprintf(file_out, "GTModelTypeGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                 }
                  break;
                case 1025: // GTRasterTypeGeoKey 
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 1: // RasterPixelIsArea   
                    fprintf(file_out, "GTRasterTypeGeoKey: RasterPixelIsArea\012");
                    break;
                  case 2: // RasterPixelIsPoint
                    fprintf(file_out, "GTRasterTypeGeoKey: RasterPixelIsPoint\012");
                    break;
                 default:
                    fprintf(file_out, "GTRasterTypeGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 1026: // GTCitationGeoKey
                  if (lasreader->header.vlr_geo_ascii_params)
                  {
                    char dummy[256];
                    strncpy(dummy, &(lasreader->header.vlr_geo_ascii_params[lasreader->header.vlr_geo_key_entries[j].value_offset]), lasreader->header.vlr_geo_key_entries[j].count);
                    dummy[lasreader->header.vlr_geo_key_entries[j].count-1] = '\0';
                    fprintf(file_out, "GTCitationGeoKey: %s\012",dummy);
                  }
                  break;
                case 2048: // GeographicTypeGeoKey 
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 32767: // user-defined
                    fprintf(file_out, "GeographicTypeGeoKey: user-defined\012");
                    break;
                  case 4001: // GCSE_Airy1830
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Airy1830\012");
                    break;
                  case 4002: // GCSE_AiryModified1849 
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_AiryModified1849\012");
                    break;
                  case 4003: // GCSE_AustralianNationalSpheroid
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_AustralianNationalSpheroid\012");
                    break;
                  case 4004: // GCSE_Bessel1841
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Bessel1841\012");
                    break;
                  case 4005: // GCSE_Bessel1841Modified
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Bessel1841Modified\012");
                    break;
                  case 4006: // GCSE_BesselNamibia
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_BesselNamibia\012");
                    break;
                  case 4008: // GCSE_Clarke1866
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Clarke1866\012");
                    break;
                  case 4009: // GCSE_Clarke1866Michigan
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Clarke1866Michigan\012");
                    break;
                  case 4010: // GCSE_Clarke1880_Benoit
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Clarke1880_Benoit\012");
                    break;
                  case 4011: // GCSE_Clarke1880_IGN
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Clarke1880_IGN\012");
                    break;
                  case 4012: // GCSE_Clarke1880_RGS
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Clarke1880_RGS\012");
                    break;
                  case 4013: // GCSE_Clarke1880_Arc
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Clarke1880_Arc\012");
                    break;
                  case 4014: // GCSE_Clarke1880_SGA1922
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Clarke1880_SGA1922\012");
                    break;
                  case 4015: // GCSE_Everest1830_1937Adjustment
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Everest1830_1937Adjustment\012");
                    break;
                  case 4016: // GCSE_Everest1830_1967Definition
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Everest1830_1967Definition\012");
                    break;
                  case 4017: // GCSE_Everest1830_1975Definition
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Everest1830_1975Definition\012");
                    break;
                  case 4018: // GCSE_Everest1830Modified
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Everest1830Modified\012");
                    break;
                  case 4019: // GCSE_GRS1980
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_GRS1980\012");
                    break;
                  case 4020: // GCSE_Helmert1906
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Helmert1906\012");
                    break;
                  case 4022: // GCSE_International1924
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_International1924\012");
                    break;
                  case 4023: // GCSE_International1967
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_International1967\012");
                    break;
                  case 4024: // GCSE_Krassowsky1940
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Krassowsky1940\012");
                    break;
                  case 4030: // GCSE_WGS84
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_WGS84\012");
                    break;
                  case 4034: // GCSE_Clarke1880
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_Clarke1880\012");
                    break;
                  case 4140: // GCSE_NAD83_CSRS
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_NAD83_CSRS\012");
                    break;
                  case 4167: // GCSE_New_Zealand_Geodetic_Datum_2000
                    fprintf(file_out, "GeographicTypeGeoKey: GCSE_New_Zealand_Geodetic_Datum_2000\012");
                    break;
                  case 4267: // GCS_NAD27
                    fprintf(file_out, "GeographicTypeGeoKey: GCS_NAD27\012");
                    break;
                  case 4269: // GCS_NAD83
                    fprintf(file_out, "GeographicTypeGeoKey: GCS_NAD83\012");
                    break;
                  case 4283: // GCS_GDA94
                    fprintf(file_out, "GeographicTypeGeoKey: GCS_GDA94\012");
                    break;
                  case 4322: // GCS_WGS_72
                    fprintf(file_out, "GeographicTypeGeoKey: GCS_WGS_72\012");
                    break;
                  case 4326: // GCS_WGS_84
                    fprintf(file_out, "GeographicTypeGeoKey: GCS_WGS_84\012");
                    break;
                  case 4289: // GCS_Amersfoort
                    fprintf(file_out, "GeographicTypeGeoKey: GCS_Amersfoort\012");
                    break;
                  case 4617: // GCS_NAD83_CSRS
                    fprintf(file_out, "GeographicTypeGeoKey: GCS_NAD83_CSRS\012");
                    break;
                  case 4619: // GCS_SWEREF99
                    fprintf(file_out, "GeographicTypeGeoKey: GCS_SWEREF99\012");
                    break;
                  default:
                    fprintf(file_out, "GeographicTypeGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 2049: // GeogCitationGeoKey
                  if (lasreader->header.vlr_geo_ascii_params)
                  {
                    char dummy[256];
                    strncpy(dummy, &(lasreader->header.vlr_geo_ascii_params[lasreader->header.vlr_geo_key_entries[j].value_offset]), lasreader->header.vlr_geo_key_entries[j].count);
                    dummy[lasreader->header.vlr_geo_key_entries[j].count-1] = '\0';
                    fprintf(file_out, "GeogCitationGeoKey: %s\012",dummy);
                  }
                  break;
                case 2050: // GeogGeodeticDatumGeoKey 
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 32767: // user-defined
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: user-defined\012");
                    break;
                  case 6202: // Datum_Australian_Geodetic_Datum_1966
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_Australian_Geodetic_Datum_1966\012");
                    break;
                  case 6203: // Datum_Australian_Geodetic_Datum_1984
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_Australian_Geodetic_Datum_1984\012");
                    break;
                  case 6267: // Datum_North_American_Datum_1927
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_North_American_Datum_1927\012");
                    break;
                  case 6269: // Datum_North_American_Datum_1983
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_North_American_Datum_1983\012");
                    break;
                  case 6283: // Datum_Geocentric_Datum_of_Australia_1994
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_Geocentric_Datum_of_Australia_1994\012");
                    break;
                  case 6322: // Datum_WGS72
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_WGS72\012");
                    break;
                  case 6326: // Datum_WGS84
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_WGS84\012");
                    break;
                  case 6140: // Datum_WGS84
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_NAD83_CSRS\012");
                    break;
                  case 6619: // Datum_SWEREF99
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_SWEREF99\012");
                    break;
                  case 6289: // Datum_Amersfoort
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_Amersfoort\012");
                    break;
                  case 6167: // Datum_NZGD2000
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: Datum_NZGD2000\012");
                    break;
                  case 6001: // DatumE_Airy1830
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Airy1830\012");
                    break;
                  case 6002: // DatumE_AiryModified1849
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_AiryModified1849\012");
                    break;
                  case 6003: // DatumE_AustralianNationalSpheroid
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_AustralianNationalSpheroid\012");
                    break;
                  case 6004: // DatumE_Bessel1841
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Bessel1841\012");
                    break;
                  case 6005: // DatumE_BesselModified
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_BesselModified\012");
                    break;
                  case 6006: // DatumE_BesselNamibia
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_BesselNamibia\012");
                    break;
                  case 6008: // DatumE_Clarke1866
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Clarke1866\012");
                    break;
                  case 6009: // DatumE_Clarke1866Michigan
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Clarke1866Michigan\012");
                    break;
                  case 6010: // DatumE_Clarke1880_Benoit
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Clarke1880_Benoit\012");
                    break;
                  case 6011: // DatumE_Clarke1880_IGN
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Clarke1880_IGN\012");
                    break;
                  case 6012: // DatumE_Clarke1880_RGS
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Clarke1880_RGS\012");
                    break;
                  case 6013: // DatumE_Clarke1880_Arc
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Clarke1880_Arc\012");
                    break;
                  case 6014: // DatumE_Clarke1880_SGA1922
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Clarke1880_SGA1922\012");
                    break;
                  case 6015: // DatumE_Everest1830_1937Adjustment
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Everest1830_1937Adjustment\012");
                    break;
                  case 6016: // DatumE_Everest1830_1967Definition
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Everest1830_1967Definition\012");
                    break;
                  case 6017: // DatumE_Everest1830_1975Definition
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Everest1830_1975Definition\012");
                    break;
                  case 6018: // DatumE_Everest1830Modified
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Everest1830Modified\012");
                    break;
                  case 6019: // DatumE_GRS1980
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_GRS1980\012");
                    break;
                  case 6020: // DatumE_Helmert1906
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Helmert1906\012");
                    break;
                  case 6022: // DatumE_International1924
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_International1924\012");
                    break;
                  case 6023: // DatumE_International1967
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_International1967\012");
                    break;
                  case 6024: // DatumE_Krassowsky1940
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Krassowsky1940\012");
                    break;
                  case 6030: // DatumE_WGS84
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_WGS84\012");
                    break;
                  case 6034: // DatumE_Clarke1880
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: DatumE_Clarke1880\012");
                    break;
                  default:
                    fprintf(file_out, "GeogGeodeticDatumGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 2051: // GeogPrimeMeridianGeoKey
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 32767: // user-defined
                    fprintf(file_out, "GeogPrimeMeridianGeoKey: user-defined\012");
                    break;
                  case 8901: // PM_Greenwich
                    fprintf(file_out, "GeogPrimeMeridianGeoKey: PM_Greenwich\012");
                    break;
                  case 8902: // PM_Lisbon
                    fprintf(file_out, "GeogPrimeMeridianGeoKey: PM_Lisbon\012");
                    break;
                  default:
                    fprintf(file_out, "GeogPrimeMeridianGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 2052: // GeogLinearUnitsGeoKey 
                  horizontal_units = lasreader->header.vlr_geo_key_entries[j].value_offset;
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 9001: // Linear_Meter
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Meter\012");
                    break;
                  case 9002: // Linear_Foot
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Foot\012");
                    break;
                  case 9003: // Linear_Foot_US_Survey
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Foot_US_Survey\012");
                    break;
                  case 9004: // Linear_Foot_Modified_American
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Foot_Modified_American\012");
                    break;
                  case 9005: // Linear_Foot_Clarke
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Foot_Clarke\012");
                    break;
                  case 9006: // Linear_Foot_Indian
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Foot_Indian\012");
                    break;
                  case 9007: // Linear_Link
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Link\012");
                    break;
                  case 9008: // Linear_Link_Benoit
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Link_Benoit\012");
                    break;
                  case 9009: // Linear_Link_Sears
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Link_Sears\012");
                    break;
                  case 9010: // Linear_Chain_Benoit
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Chain_Benoit\012");
                    break;
                  case 9011: // Linear_Chain_Sears
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Chain_Sears\012");
                    break;
                  case 9012: // Linear_Yard_Sears
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Yard_Sears\012");
                    break;
                  case 9013: // Linear_Yard_Indian
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Yard_Indian\012");
                    break;
                  case 9014: // Linear_Fathom
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Fathom\012");
                    break;
                  case 9015: // Linear_Mile_International_Nautical
                    fprintf(file_out, "GeogLinearUnitsGeoKey: Linear_Mile_International_Nautical\012");
                    break;
                  default:
                    fprintf(file_out, "GeogLinearUnitsGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 2053: // GeogLinearUnitSizeGeoKey  
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "GeogLinearUnitSizeGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 2054: // GeogAngularUnitsGeoKey
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 9101: // Angular_Radian
                    fprintf(file_out, "GeogAngularUnitsGeoKey: Angular_Radian\012");
                    break;
                  case 9102: // Angular_Degree
                    fprintf(file_out, "GeogAngularUnitsGeoKey: Angular_Degree\012");
                    break;
                  case 9103: // Angular_Arc_Minute
                    fprintf(file_out, "GeogAngularUnitsGeoKey: Angular_Arc_Minute\012");
                    break;
                  case 9104: // Angular_Arc_Second
                    fprintf(file_out, "GeogAngularUnitsGeoKey: Angular_Arc_Second\012");
                    break;
                  case 9105: // Angular_Grad
                    fprintf(file_out, "GeogAngularUnitsGeoKey: Angular_Grad\012");
                    break;
                  case 9106: // Angular_Gon
                    fprintf(file_out, "GeogAngularUnitsGeoKey: Angular_Gon\012");
                    break;
                  case 9107: // Angular_DMS
                    fprintf(file_out, "GeogAngularUnitsGeoKey: Angular_DMS\012");
                    break;
                  case 9108: // Angular_DMS_Hemisphere
                    fprintf(file_out, "GeogAngularUnitsGeoKey: Angular_DMS_Hemisphere\012");
                    break;
                  default:
                    fprintf(file_out, "GeogAngularUnitsGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 2055: // GeogAngularUnitSizeGeoKey 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "GeogAngularUnitSizeGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 2056: // GeogEllipsoidGeoKey
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 32767: // user-defined
                    fprintf(file_out, "GeogEllipsoidGeoKey: user-defined\012");
                    break;
                  case 7001: // Ellipse_Airy_1830
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Airy_1830\012");
                    break;
                  case 7002: // Ellipse_Airy_Modified_1849
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Airy_Modified_1849\012");
                    break;
                  case 7003: // Ellipse_Australian_National_Spheroid
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Australian_National_Spheroid\012");
                    break;
                  case 7004: // Ellipse_Bessel_1841
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Bessel_1841\012");
                    break;
                  case 7005: // Ellipse_Bessel_Modified
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Bessel_Modified\012");
                    break;
                  case 7006: // Ellipse_Bessel_Namibia
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Bessel_Namibia\012");
                    break;
                  case 7008: // Ellipse_Clarke_1866
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Clarke_1866\012");
                    break;
                  case 7009: // Ellipse_Clarke_1866_Michigan
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Clarke_1866_Michigan\012");
                    break;
                  case 7010: // Ellipse_Clarke1880_Benoit
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Clarke1880_Benoit\012");
                    break;
                  case 7011: // Ellipse_Clarke1880_IGN
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Clarke1880_IGN\012");
                    break;
                  case 7012: // Ellipse_Clarke1880_RGS
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Clarke1880_RGS\012");
                    break;
                  case 7013: // Ellipse_Clarke1880_Arc
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Clarke1880_Arc\012");
                    break;
                  case 7014: // Ellipse_Clarke1880_SGA1922
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Clarke1880_SGA1922\012");
                    break;
                  case 7015: // Ellipse_Everest1830_1937Adjustment
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Everest1830_1937Adjustment\012");
                    break;
                  case 7016: // Ellipse_Everest1830_1967Definition
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Everest1830_1967Definition\012");
                    break;
                  case 7017: // Ellipse_Everest1830_1975Definition
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Everest1830_1975Definition\012");
                    break;
                  case 7018: // Ellipse_Everest1830Modified
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Everest1830Modified\012");
                    break;
                  case 7019: // Ellipse_GRS_1980
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_GRS_1980\012");
                    break;
                  case 7020: // Ellipse_Helmert1906
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Helmert1906\012");
                    break;
                  case 7022: // Ellipse_International1924
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_International1924\012");
                    break;
                  case 7023: // Ellipse_International1967
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_International1967\012");
                    break;
                  case 7024: // Ellipse_Krassowsky1940
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Krassowsky1940\012");
                    break;
                  case 7030: // Ellipse_WGS_84
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_WGS_84\012");
                    break;
                  case 7034: // Ellipse_Clarke_1880
                    fprintf(file_out, "GeogEllipsoidGeoKey: Ellipse_Clarke_1880\012");
                    break;
                  default:
                    fprintf(file_out, "GeogEllipsoidGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 2057: // GeogSemiMajorAxisGeoKey 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "GeogSemiMajorAxisGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 2058: // GeogSemiMinorAxisGeoKey 
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "GeogSemiMinorAxisGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 2059: // GeogInvFlatteningGeoKey
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "GeogInvFlatteningGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 2060: // GeogAzimuthUnitsGeoKey
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 9101: // Angular_Radian
                    fprintf(file_out, "GeogAzimuthUnitsGeoKey: Angular_Radian\012");
                    break;
                  case 9102: // Angular_Degree
                    fprintf(file_out, "GeogAzimuthUnitsGeoKey: Angular_Degree\012");
                    break;
                  case 9103: // Angular_Arc_Minute
                    fprintf(file_out, "GeogAzimuthUnitsGeoKey: Angular_Arc_Minute\012");
                    break;
                  case 9104: // Angular_Arc_Second
                    fprintf(file_out, "GeogAzimuthUnitsGeoKey: Angular_Arc_Second\012");
                    break;
                  case 9105: // Angular_Grad
                    fprintf(file_out, "GeogAzimuthUnitsGeoKey: Angular_Grad\012");
                    break;
                  case 9106: // Angular_Gon
                    fprintf(file_out, "GeogAzimuthUnitsGeoKey: Angular_Gon\012");
                    break;
                  case 9107: // Angular_DMS
                    fprintf(file_out, "GeogAzimuthUnitsGeoKey: Angular_DMS\012");
                    break;
                  case 9108: // Angular_DMS_Hemisphere
                    fprintf(file_out, "GeogAzimuthUnitsGeoKey: Angular_DMS_Hemisphere\012");
                    break;
                  default:
                    fprintf(file_out, "GeogAzimuthUnitsGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 2061: // GeogPrimeMeridianLongGeoKey  
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "GeogPrimeMeridianLongGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 2062: // GeogTOWGS84GeoKey
                  switch (lasreader->header.vlr_geo_key_entries[j].count)
                  {
                  case 3:
                    if (lasreader->header.vlr_geo_double_params)
                    {
                      fprintf(file_out, "GeogTOWGS84GeoKey: TOWGS84[%.10g,%.10g,%.10g]\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset], lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset+1], lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset+2]);
                    }
                    else
                    {
                      fprintf(file_out, "GeogTOWGS84GeoKey: no vlr_geo_double_params. cannot look up the three parameters.\012");
                    }
                    break;
                  case 7:
                    if (lasreader->header.vlr_geo_double_params)
                    {
                      fprintf(file_out, "GeogTOWGS84GeoKey: TOWGS84[%.10g,%.10g,%.10g,%.10g,%.10g,%.10g,%.10g]\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset], lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset+1], lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset+2], lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset+3], lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset+4], lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset+5], lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset+6]);
                    }
                    else
                    {
                      fprintf(file_out, "GeogTOWGS84GeoKey: no vlr_geo_double_params. cannot look up the seven parameters.\012");
                    }
                    break;
                  default:
                    fprintf(file_out, "GeogTOWGS84GeoKey: look-up for type %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].count);
                  }
                  break;
                case 3072: // ProjectedCSTypeGeoKey
                  if (geoprojectionconverter.set_ProjectedCSTypeGeoKey(lasreader->header.vlr_geo_key_entries[j].value_offset, printstring))
                  {
                    horizontal_units = geoprojectionconverter.get_ProjLinearUnitsGeoKey();
                    fprintf(file_out, "ProjectedCSTypeGeoKey: %s\012", printstring);
                    break;
                  }
                  else
                  {
                    fprintf(file_out, "ProjectedCSTypeGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 3073: // PCSCitationGeoKey
                  if (lasreader->header.vlr_geo_ascii_params)
                  {
                    char dummy[256];
                    strncpy(dummy, &(lasreader->header.vlr_geo_ascii_params[lasreader->header.vlr_geo_key_entries[j].value_offset]), lasreader->header.vlr_geo_key_entries[j].count);
                    dummy[lasreader->header.vlr_geo_key_entries[j].count-1] = '\0';
                    fprintf(file_out, "PCSCitationGeoKey: %s\012",dummy);
                  }
                  break;
                case 3074: // ProjectionGeoKey
                  if ((16001 <= lasreader->header.vlr_geo_key_entries[j].value_offset) && (lasreader->header.vlr_geo_key_entries[j].value_offset <= 16060))
                  {
                    fprintf(file_out, "ProjectionGeoKey: Proj_UTM_zone_%dN\012", lasreader->header.vlr_geo_key_entries[j].value_offset - 16000);
                  }
                  else if ((16101 <= lasreader->header.vlr_geo_key_entries[j].value_offset) && (lasreader->header.vlr_geo_key_entries[j].value_offset <= 16160))
                  {
                    fprintf(file_out, "ProjectionGeoKey: Proj_UTM_zone_%dS\012", lasreader->header.vlr_geo_key_entries[j].value_offset - 16100);
                  }
                  else
                  {
                    switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                    {
                    case 32767: // user-defined
                      fprintf(file_out, "ProjectionGeoKey: user-defined\012");
                      break;
                    case 10101: // Proj_Alabama_CS27_East
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alabama_CS27_East\012");
                      break;
                    case 10102: // Proj_Alabama_CS27_West
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alabama_CS27_West\012");
                      break;
                    case 10131: // Proj_Alabama_CS83_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alabama_CS83_East\012");
                      break;
                    case 10132: // Proj_Alabama_CS83_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alabama_CS83_West\012");
                      break;
                    case 10201: // Proj_Arizona_Coordinate_System_east			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Arizona_Coordinate_System_east\012");
                      break;
                    case 10202: // Proj_Arizona_Coordinate_System_Central		
                      fprintf(file_out, "ProjectionGeoKey: Proj_Arizona_Coordinate_System_Central\012");
                      break;
                    case 10203: // Proj_Arizona_Coordinate_System_west			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Arizona_Coordinate_System_west\012");
                      break;
                    case 10231: // Proj_Arizona_CS83_east				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Arizona_CS83_east\012");
                      break;
                    case 10232: // Proj_Arizona_CS83_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Arizona_CS83_Central\012");
                      break;
                    case 10233: // Proj_Arizona_CS83_west				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Arizona_CS83_west\012");
                      break;
                    case 10301: // Proj_Arkansas_CS27_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Arkansas_CS27_North\012");
                      break;
                    case 10302: // Proj_Arkansas_CS27_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Arkansas_CS27_South\012");
                      break;
                    case 10331: // Proj_Arkansas_CS83_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Arkansas_CS83_North\012");
                      break;
                    case 10332: // Proj_Arkansas_CS83_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Arkansas_CS83_South\012");
                      break;
                    case 10401: // Proj_California_CS27_I				
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS27_I\012");
                      break;
                    case 10402: // Proj_California_CS27_II				
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS27_II\012");
                      break;
                    case 10403: // Proj_California_CS27_III				
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS27_III\012");
                      break;
                    case 10404: // Proj_California_CS27_IV				
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS27_IV\012");
                      break;
                    case 10405: // Proj_California_CS27_V				
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS27_V\012");
                      break;
                    case 10406: // Proj_California_CS27_VI				
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS27_VI\012");
                      break;
                    case 10407: // Proj_California_CS27_VII				
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS27_VII\012");
                      break;
                    case 10431: // Proj_California_CS83_1				
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS83_1\012");
                      break;
                    case 10432: // Proj_California_CS83_2				
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS83_2\012");
                      break;
                    case 10433: // Proj_California_CS83_3				
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS83_3\012");
                      break;
                    case 10434: // Proj_California_CS83_4				
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS83_4\012");
                      break;
                    case 10435: // Proj_California_CS83_5				
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS83_5\012");
                      break;
                    case 10436: // Proj_California_CS83_6				
                      fprintf(file_out, "ProjectionGeoKey: Proj_California_CS83_6\012");
                      break;
                    case 10501: // Proj_Colorado_CS27_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Colorado_CS27_North\012");
                      break;
                    case 10502: // Proj_Colorado_CS27_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Colorado_CS27_Central\012");
                      break;
                    case 10503: // Proj_Colorado_CS27_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Colorado_CS27_South\012");
                      break;
                    case 10531: // Proj_Colorado_CS83_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Colorado_CS83_North\012");
                      break;
                    case 10532: // Proj_Colorado_CS83_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Colorado_CS83_Central\012");
                      break;
                    case 10533: // Proj_Colorado_CS83_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Colorado_CS83_South\012");
                      break;
                    case 10600: // Proj_Connecticut_CS27				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Connecticut_CS27\012");
                      break;
                    case 10630: // Proj_Connecticut_CS83				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Connecticut_CS83\012");
                      break;
                    case 10700: // Proj_Delaware_CS27					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Delaware_CS27\012");
                      break;
                    case 10730: // Proj_Delaware_CS83					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Delaware_CS83\012");
                      break;
                    case 10901: // Proj_Florida_CS27_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Florida_CS27_East\012");
                      break;
                    case 10902: // Proj_Florida_CS27_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Florida_CS27_West\012");
                      break;
                    case 10903: // Proj_Florida_CS27_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Florida_CS27_North\012");
                      break;
                    case 10931: // Proj_Florida_CS83_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Florida_CS83_East\012");
                      break;
                    case 10932: // Proj_Florida_CS83_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Florida_CS83_West\012");
                      break;
                    case 10933: // Proj_Florida_CS83_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Florida_CS83_North\012");
                      break;
                    case 11001: // Proj_Georgia_CS27_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Georgia_CS27_East\012");
                      break;
                    case 11002: // Proj_Georgia_CS27_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Georgia_CS27_West\012");
                      break;
                    case 11031: // Proj_Georgia_CS83_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Georgia_CS83_East\012");
                      break;
                    case 11032: // Proj_Georgia_CS83_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Georgia_CS83_West\012");
                      break;
                    case 11101: // Proj_Idaho_CS27_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Idaho_CS27_East\012");
                      break;
                    case 11102: // Proj_Idaho_CS27_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Idaho_CS27_Central\012");
                      break;
                    case 11103: // Proj_Idaho_CS27_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Idaho_CS27_West\012");
                      break;
                    case 11131: // Proj_Idaho_CS83_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Idaho_CS83_East\012");
                      break;
                    case 11132: // Proj_Idaho_CS83_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Idaho_CS83_Central\012");
                      break;
                    case 11133: // Proj_Idaho_CS83_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Idaho_CS83_West\012");
                      break;
                    case 11201: // Proj_Illinois_CS27_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Illinois_CS27_East\012");
                      break;
                    case 11202: // Proj_Illinois_CS27_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Illinois_CS27_West\012");
                      break;
                    case 11231: // Proj_Illinois_CS83_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Illinois_CS83_East\012");
                      break;
                    case 11232: // Proj_Illinois_CS83_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Illinois_CS83_West\012");
                      break;
                    case 11301: // Proj_Indiana_CS27_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Indiana_CS27_East\012");
                      break;
                    case 11302: // Proj_Indiana_CS27_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Indiana_CS27_West\012");
                      break;
                    case 11331: // Proj_Indiana_CS83_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Indiana_CS83_East\012");
                      break;
                    case 11332: // Proj_Indiana_CS83_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Indiana_CS83_West\012");
                      break;
                    case 11401: // Proj_Iowa_CS27_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Iowa_CS27_North\012");
                      break;
                    case 11402: // Proj_Iowa_CS27_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Iowa_CS27_South\012");
                      break;
                    case 11431: // Proj_Iowa_CS83_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Iowa_CS83_North\012");
                      break;
                    case 11432: // Proj_Iowa_CS83_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Iowa_CS83_South\012");
                      break;
                    case 11501: // Proj_Kansas_CS27_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Kansas_CS27_North\012");
                      break;
                    case 11502: // Proj_Kansas_CS27_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Kansas_CS27_South\012");
                      break;
                    case 11531: // Proj_Kansas_CS83_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Kansas_CS83_North\012");
                      break;
                    case 11532: // Proj_Kansas_CS83_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Kansas_CS83_South\012");
                      break;
                    case 11601: // Proj_Kentucky_CS27_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Kentucky_CS27_North\012");
                      break;
                    case 11602: // Proj_Kentucky_CS27_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Kentucky_CS27_South\012");
                      break;
                    case 11631: // Proj_Kentucky_CS83_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Kentucky_CS83_North\012");
                      break;
                    case 11632: // Proj_Kentucky_CS83_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Kentucky_CS83_South\012");
                      break;
                    case 11701: // Proj_Louisiana_CS27_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Louisiana_CS27_North\012");
                      break;
                    case 11702: // Proj_Louisiana_CS27_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Louisiana_CS27_South\012");
                      break;
                    case 11731: // Proj_Louisiana_CS83_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Louisiana_CS83_North\012");
                      break;
                    case 11732: // Proj_Louisiana_CS83_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Louisiana_CS83_South\012");
                      break;
                    case 11801: // Proj_Maine_CS27_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Maine_CS27_East\012");
                      break;
                    case 11802: // Proj_Maine_CS27_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Maine_CS27_West\012");
                      break;
                    case 11831: // Proj_Maine_CS83_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Maine_CS83_East\012");
                      break;
                    case 11832: // Proj_Maine_CS83_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Maine_CS83_West\012");
                      break;
                    case 11900: // Proj_Maryland_CS27					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Maryland_CS27\012");
                      break;
                    case 11930: // Proj_Maryland_CS83					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Maryland_CS83\012");
                      break;
                    case 12001: // Proj_Massachusetts_CS27_Mainland			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Massachusetts_CS27_Mainland\012");
                      break;
                    case 12002: // Proj_Massachusetts_CS27_Island			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Massachusetts_CS27_Island\012");
                      break;
                    case 12031: // Proj_Massachusetts_CS83_Mainland			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Massachusetts_CS83_Mainland\012");
                      break;
                    case 12032: // Proj_Massachusetts_CS83_Island			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Massachusetts_CS83_Island\012");
                      break;
                    case 12101: // Proj_Michigan_State_Plane_East			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Michigan_State_Plane_East\012");
                      break;
                    case 12102: // Proj_Michigan_State_Plane_Old_Central		
                      fprintf(file_out, "ProjectionGeoKey: Proj_Michigan_State_Plane_Old_Central\012");
                      break;
                    case 12103: // Proj_Michigan_State_Plane_West			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Michigan_State_Plane_West\012");
                      break;
                    case 12111: // Proj_Michigan_CS27_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Michigan_CS27_North\012");
                      break;
                    case 12112: // Proj_Michigan_CS27_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Michigan_CS27_Central\012");
                      break;
                    case 12113: // Proj_Michigan_CS27_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Michigan_CS27_South\012");
                      break;
                    case 12141: // Proj_Michigan_CS83_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Michigan_CS83_North\012");
                      break;
                    case 12142: // Proj_Michigan_CS83_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Michigan_CS83_Central\012");
                      break;
                    case 12143: // Proj_Michigan_CS83_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Michigan_CS83_South\012");
                      break;
                    case 12201: // Proj_Minnesota_CS27_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Minnesota_CS27_North\012");
                      break;
                    case 12202: // Proj_Minnesota_CS27_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Minnesota_CS27_Central\012");
                      break;
                    case 12203: // Proj_Minnesota_CS27_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Minnesota_CS27_South\012");
                      break;
                    case 12231: // Proj_Minnesota_CS83_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Minnesota_CS83_North\012");
                      break;
                    case 12232: // Proj_Minnesota_CS83_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Minnesota_CS83_Central\012");
                      break;
                    case 12233: // Proj_Minnesota_CS83_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Minnesota_CS83_South\012");
                      break;
                    case 12301: // Proj_Mississippi_CS27_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Mississippi_CS27_East\012");
                      break;
                    case 12302: // Proj_Mississippi_CS27_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Mississippi_CS27_West\012");
                      break;
                    case 12331: // Proj_Mississippi_CS83_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Mississippi_CS83_East\012");
                      break;
                    case 12332: // Proj_Mississippi_CS83_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Mississippi_CS83_West\012");
                      break;
                    case 12401: // Proj_Missouri_CS27_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Missouri_CS27_East\012");
                      break;
                    case 12402: // Proj_Missouri_CS27_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Missouri_CS27_Central\012");
                      break;
                    case 12403: // Proj_Missouri_CS27_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Missouri_CS27_West\012");
                      break;
                    case 12431: // Proj_Missouri_CS83_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Missouri_CS83_East\012");
                      break;
                    case 12432: // Proj_Missouri_CS83_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Missouri_CS83_Central\012");
                      break;
                    case 12433: // Proj_Missouri_CS83_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Missouri_CS83_West\012");
                      break;
                    case 12501: // Proj_Montana_CS27_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Montana_CS27_North\012");
                      break;
                    case 12502: // Proj_Montana_CS27_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Montana_CS27_Central\012");
                      break;
                    case 12503: // Proj_Montana_CS27_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Montana_CS27_South\012");
                      break;
                    case 12530: // Proj_Montana_CS83					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Montana_CS83\012");
                      break;
                    case 12601: // Proj_Nebraska_CS27_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Nebraska_CS27_North\012");
                      break;
                    case 12602: // Proj_Nebraska_CS27_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Nebraska_CS27_South\012");
                      break;
                    case 12630: // Proj_Nebraska_CS83					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Nebraska_CS83\012");
                      break;
                    case 12701: // Proj_Nevada_CS27_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Nevada_CS27_East\012");
                      break;
                    case 12702: // Proj_Nevada_CS27_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Nevada_CS27_Central\012");
                      break;
                    case 12703: // Proj_Nevada_CS27_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Nevada_CS27_West\012");
                      break;
                    case 12731: // Proj_Nevada_CS83_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Nevada_CS83_East\012");
                      break;
                    case 12732: // Proj_Nevada_CS83_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Nevada_CS83_Central\012");
                      break;
                    case 12733: // Proj_Nevada_CS83_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Nevada_CS83_West\012");
                      break;
                    case 12800: // Proj_New_Hampshire_CS27				
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Hampshire_CS27\012");
                      break;
                    case 12830: // Proj_New_Hampshire_CS83				
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Hampshire_CS83\012");
                      break;
                    case 12900: // Proj_New_Jersey_CS27				
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Jersey_CS27\012");
                      break;
                    case 12930: // Proj_New_Jersey_CS83				
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Jersey_CS83\012");
                      break;
                    case 13001: // Proj_New_Mexico_CS27_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Mexico_CS27_East\012");
                      break;
                    case 13002: // Proj_New_Mexico_CS27_Central			
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Mexico_CS27_Central\012");
                      break;
                    case 13003: // Proj_New_Mexico_CS27_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Mexico_CS27_West\012");
                      break;
                    case 13031: // Proj_New_Mexico_CS83_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Mexico_CS83_East\012");
                      break;
                    case 13032: // Proj_New_Mexico_CS83_Central			
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Mexico_CS83_Central\012");
                      break;
                    case 13033: // Proj_New_Mexico_CS83_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Mexico_CS83_West\012");
                      break;
                    case 13101: // Proj_New_York_CS27_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_York_CS27_East\012");
                      break;
                    case 13102: // Proj_New_York_CS27_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_York_CS27_Central\012");
                      break;
                    case 13103: // Proj_New_York_CS27_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_York_CS27_West\012");
                      break;
                    case 13104: // Proj_New_York_CS27_Long_Island			
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_York_CS27_Long_Island\012");
                      break;
                    case 13131: // Proj_New_York_CS83_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_York_CS83_East\012");
                      break;
                    case 13132: // Proj_New_York_CS83_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_York_CS83_Central\012");
                      break;
                    case 13133: // Proj_New_York_CS83_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_York_CS83_West\012");
                      break;
                    case 13134: // Proj_New_York_CS83_Long_Island			
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_York_CS83_Long_Island\012");
                      break;
                    case 13200: // Proj_North_Carolina_CS27				
                      fprintf(file_out, "ProjectionGeoKey: Proj_North_Carolina_CS27\012");
                      break;
                    case 13230: // Proj_North_Carolina_CS83				
                      fprintf(file_out, "ProjectionGeoKey: Proj_North_Carolina_CS83\012");
                      break;
                    case 13301: // Proj_North_Dakota_CS27_North			
                      fprintf(file_out, "ProjectionGeoKey: Proj_North_Dakota_CS27_North\012");
                      break;
                    case 13302: // Proj_North_Dakota_CS27_South			
                      fprintf(file_out, "ProjectionGeoKey: Proj_North_Dakota_CS27_South\012");
                      break;
                    case 13331: // Proj_North_Dakota_CS83_North			
                      fprintf(file_out, "ProjectionGeoKey: Proj_North_Dakota_CS83_North\012");
                      break;
                    case 13332: // Proj_North_Dakota_CS83_South			
                      fprintf(file_out, "ProjectionGeoKey: Proj_North_Dakota_CS83_South\012");
                      break;
                    case 13401: // Proj_Ohio_CS27_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Ohio_CS27_North\012");
                      break;
                    case 13402: // Proj_Ohio_CS27_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Ohio_CS27_South\012");
                      break;
                    case 13431: // Proj_Ohio_CS83_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Ohio_CS83_North\012");
                      break;
                    case 13432: // Proj_Ohio_CS83_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Ohio_CS83_South\012");
                      break;
                    case 13501: // Proj_Oklahoma_CS27_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Oklahoma_CS27_North\012");
                      break;
                    case 13502: // Proj_Oklahoma_CS27_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Oklahoma_CS27_South\012");
                      break;
                    case 13531: // Proj_Oklahoma_CS83_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Oklahoma_CS83_North\012");
                      break;
                    case 13532: // Proj_Oklahoma_CS83_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Oklahoma_CS83_South\012");
                      break;
                    case 13601: // Proj_Oregon_CS27_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Oregon_CS27_North\012");
                      break;
                    case 13602: // Proj_Oregon_CS27_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Oregon_CS27_South\012");
                      break;
                    case 13631: // Proj_Oregon_CS83_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Oregon_CS83_North\012");
                      break;
                    case 13632: // Proj_Oregon_CS83_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Oregon_CS83_South\012");
                      break;
                    case 13701: // Proj_Pennsylvania_CS27_North			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Pennsylvania_CS27_North\012");
                      break;
                    case 13702: // Proj_Pennsylvania_CS27_South			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Pennsylvania_CS27_South\012");
                      break;
                    case 13731: // Proj_Pennsylvania_CS83_North			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Pennsylvania_CS83_North\012");
                      break;
                    case 13732: // Proj_Pennsylvania_CS83_South			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Pennsylvania_CS83_South\012");
                      break;
                    case 13800: // Proj_Rhode_Island_CS27				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Rhode_Island_CS27\012");
                      break;
                    case 13830: // Proj_Rhode_Island_CS83				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Rhode_Island_CS83\012");
                      break;
                    case 13901: // Proj_South_Carolina_CS27_North			
                      fprintf(file_out, "ProjectionGeoKey: Proj_South_Carolina_CS27_North\012");
                      break;
                    case 13902: // Proj_South_Carolina_CS27_South			
                      fprintf(file_out, "ProjectionGeoKey: Proj_South_Carolina_CS27_South\012");
                      break;
                    case 13930: // Proj_South_Carolina_CS83				
                      fprintf(file_out, "ProjectionGeoKey: Proj_South_Carolina_CS83\012");
                      break;
                    case 14001: // Proj_South_Dakota_CS27_North			
                      fprintf(file_out, "ProjectionGeoKey: Proj_South_Dakota_CS27_North\012");
                      break;
                    case 14002: // Proj_South_Dakota_CS27_South			
                      fprintf(file_out, "ProjectionGeoKey: Proj_South_Dakota_CS27_South\012");
                      break;
                    case 14031: // Proj_South_Dakota_CS83_North			
                      fprintf(file_out, "ProjectionGeoKey: Proj_South_Dakota_CS83_North\012");
                      break;
                    case 14032: // Proj_South_Dakota_CS83_South			
                      fprintf(file_out, "ProjectionGeoKey: Proj_South_Dakota_CS83_South\012");
                      break;
                    case 14100: // Proj_Tennessee_CS27					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Tennessee_CS27\012");
                      break;
                    case 14130: // Proj_Tennessee_CS83					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Tennessee_CS83\012");
                      break;
                    case 14201: // Proj_Texas_CS27_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Texas_CS27_North\012");
                      break;
                    case 14202: // Proj_Texas_CS27_North_Central			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Texas_CS27_North_Central\012");
                      break;
                    case 14203: // Proj_Texas_CS27_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Texas_CS27_Central\012");
                      break;
                    case 14204: // Proj_Texas_CS27_South_Central			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Texas_CS27_South_Central\012");
                      break;
                    case 14205: // Proj_Texas_CS27_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Texas_CS27_South\012");
                      break;
                    case 14231: // Proj_Texas_CS83_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Texas_CS83_North\012");
                      break;
                    case 14232: // Proj_Texas_CS83_North_Central			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Texas_CS83_North_Central\012");
                      break;
                    case 14233: // Proj_Texas_CS83_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Texas_CS83_Central\012");
                      break;
                    case 14234: // Proj_Texas_CS83_South_Central			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Texas_CS83_South_Central\012");
                      break;
                    case 14235: // Proj_Texas_CS83_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Texas_CS83_South\012");
                      break;
                    case 14301: // Proj_Utah_CS27_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Utah_CS27_North\012");
                      break;
                    case 14302: // Proj_Utah_CS27_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Utah_CS27_Central\012");
                      break;
                    case 14303: // Proj_Utah_CS27_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Utah_CS27_South\012");
                      break;
                    case 14331: // Proj_Utah_CS83_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Utah_CS83_North\012");
                      break;
                    case 14332: // Proj_Utah_CS83_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Utah_CS83_Central\012");
                      break;
                    case 14333: // Proj_Utah_CS83_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Utah_CS83_South\012");
                      break;
                    case 14400: // Proj_Vermont_CS27					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Vermont_CS27\012");
                      break;
                    case 14430: // Proj_Vermont_CS83					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Vermont_CS83\012");
                      break;
                    case 14501: // Proj_Virginia_CS27_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Virginia_CS27_North\012");
                      break;
                    case 14502: // Proj_Virginia_CS27_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Virginia_CS27_South\012");
                      break;
                    case 14531: // Proj_Virginia_CS83_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Virginia_CS83_North\012");
                      break;
                    case 14532: // Proj_Virginia_CS83_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Virginia_CS83_South\012");
                      break;
                    case 14601: // Proj_Washington_CS27_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Washington_CS27_North\012");
                      break;
                    case 14602: // Proj_Washington_CS27_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Washington_CS27_South\012");
                      break;
                    case 14631: // Proj_Washington_CS83_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Washington_CS83_North\012");
                      break;
                    case 14632: // Proj_Washington_CS83_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Washington_CS83_South\012");
                      break;
                    case 14701: // Proj_West_Virginia_CS27_North			
                      fprintf(file_out, "ProjectionGeoKey: Proj_West_Virginia_CS27_North\012");
                      break;
                    case 14702: // Proj_West_Virginia_CS27_South			
                      fprintf(file_out, "ProjectionGeoKey: Proj_West_Virginia_CS27_South\012");
                      break;
                    case 14731: // Proj_West_Virginia_CS83_North			
                      fprintf(file_out, "ProjectionGeoKey: Proj_West_Virginia_CS83_North\012");
                      break;
                    case 14732: // Proj_West_Virginia_CS83_South			
                      fprintf(file_out, "ProjectionGeoKey: Proj_West_Virginia_CS83_South\012");
                      break;
                    case 14801: // Proj_Wisconsin_CS27_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wisconsin_CS27_North\012");
                      break;
                    case 14802: // Proj_Wisconsin_CS27_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wisconsin_CS27_Central\012");
                      break;
                    case 14803: // Proj_Wisconsin_CS27_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wisconsin_CS27_South\012");
                      break;
                    case 14831: // Proj_Wisconsin_CS83_North				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wisconsin_CS83_North\012");
                      break;
                    case 14832: // Proj_Wisconsin_CS83_Central				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wisconsin_CS83_Central\012");
                      break;
                    case 14833: // Proj_Wisconsin_CS83_South				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wisconsin_CS83_South\012");
                      break;
                    case 14901: // Proj_Wyoming_CS27_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wyoming_CS27_East\012");
                      break;
                    case 14902: // Proj_Wyoming_CS27_East_Central			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wyoming_CS27_East_Central\012");
                      break;
                    case 14903: // Proj_Wyoming_CS27_West_Central			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wyoming_CS27_West_Central\012");
                      break;
                    case 14904: // Proj_Wyoming_CS27_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wyoming_CS27_West\012");
                      break;
                    case 14931: // Proj_Wyoming_CS83_East				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wyoming_CS83_East\012");
                      break;
                    case 14932: // Proj_Wyoming_CS83_East_Central			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wyoming_CS83_East_Central\012");
                      break;
                    case 14933: // Proj_Wyoming_CS83_West_Central			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wyoming_CS83_West_Central\012");
                      break;
                    case 14934: // Proj_Wyoming_CS83_West				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Wyoming_CS83_West\012");
                      break;
                    case 15001: // Proj_Alaska_CS27_1					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS27_1\012");
                      break;
                    case 15002: // Proj_Alaska_CS27_2					
                      fprintf(file_out, "ProjectionGeoKey: ProjectionGeoKey\012");
                      break;
                    case 15003: // Proj_Alaska_CS27_3					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS27_3\012");
                      break;
                    case 15004: // Proj_Alaska_CS27_4					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS27_4\012");
                      break;
                    case 15005: // Proj_Alaska_CS27_5					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS27_5\012");
                      break;
                    case 15006: // Proj_Alaska_CS27_6					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS27_6\012");
                      break;
                    case 15007: // Proj_Alaska_CS27_7					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS27_7\012");
                      break;
                    case 15008: // Proj_Alaska_CS27_8					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS27_8\012");
                      break;
                    case 15009: // Proj_Alaska_CS27_9					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS27_9\012");
                      break;
                    case 15010: // Proj_Alaska_CS27_10					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS27_10\012");
                      break;
                    case 15031: // Proj_Alaska_CS83_1					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS83_1\012");
                      break;
                    case 15032: // Proj_Alaska_CS83_2					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS83_2\012");
                      break;
                    case 15033: // Proj_Alaska_CS83_3					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS83_3\012");
                      break;
                    case 15034: // Proj_Alaska_CS83_4					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS83_4\012");
                      break;
                    case 15035: // Proj_Alaska_CS83_5					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS83_5\012");
                      break;
                    case 15036: // Proj_Alaska_CS83_6					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS83_6\012");
                      break;
                    case 15037: // Proj_Alaska_CS83_7					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS83_7\012");
                      break;
                    case 15038: // Proj_Alaska_CS83_8					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS83_8\012");
                      break;
                    case 15039: // Proj_Alaska_CS83_9					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS83_9\012");
                      break;
                    case 15040: // Proj_Alaska_CS83_10					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Alaska_CS83_10\012");
                      break;
                    case 15101: // Proj_Hawaii_CS27_1					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Hawaii_CS27_1\012");
                      break;
                    case 15102: // Proj_Hawaii_CS27_2					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Hawaii_CS27_2\012");
                      break;
                    case 15103: // Proj_Hawaii_CS27_3					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Hawaii_CS27_3\012");
                      break;
                    case 15104: // Proj_Hawaii_CS27_4					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Hawaii_CS27_4\012");
                      break;
                    case 15105: // Proj_Hawaii_CS27_5					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Hawaii_CS27_5\012");
                      break;
                    case 15131: // Proj_Hawaii_CS83_1					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Hawaii_CS83_1\012");
                      break;
                    case 15132: // Proj_Hawaii_CS83_2					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Hawaii_CS83_2\012");
                      break;
                    case 15133: // Proj_Hawaii_CS83_3					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Hawaii_CS83_3\012");
                      break;
                    case 15134: // Proj_Hawaii_CS83_4					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Hawaii_CS83_4\012");
                      break;
                    case 15135: // Proj_Hawaii_CS83_5					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Hawaii_CS83_5\012");
                      break;
                    case 15201: // Proj_Puerto_Rico_CS27				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Puerto_Rico_CS27\012");
                      break;
                    case 15202: // Proj_St_Croix					
                      fprintf(file_out, "ProjectionGeoKey: Proj_St_Croix\012");
                      break;
                    case 15230: // Proj_Puerto_Rico_Virgin_Is				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Puerto_Rico_Virgin_Is\012");
                      break;
                    case 15914: // Proj_BLM_14N_feet					
                      fprintf(file_out, "ProjectionGeoKey: Proj_BLM_14N_feet\012");
                      break;
                    case 15915: // Proj_BLM_15N_feet					
                      fprintf(file_out, "ProjectionGeoKey: Proj_BLM_15N_feet\012");
                      break;
                    case 15916: // Proj_BLM_16N_feet					
                      fprintf(file_out, "ProjectionGeoKey: Proj_BLM_16N_feet\012");
                      break;
                    case 15917: // Proj_BLM_17N_feet					
                      fprintf(file_out, "ProjectionGeoKey: Proj_BLM_17N_feet\012");
                      break;
                    case 17333: // Proj_SWEREF99_TM		
                      fprintf(file_out, "ProjectionGeoKey: Proj_SWEREF99_TM\012");
                      break;
                    case 17348: // Proj_Map_Grid_of_Australia_48			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_48\012");
                      break;
                    case 17349: // Proj_Map_Grid_of_Australia_49			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_49\012");
                      break;
                    case 17350: // Proj_Map_Grid_of_Australia_50			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_50\012");
                      break;
                    case 17351: // Proj_Map_Grid_of_Australia_51			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_51\012");
                      break;
                    case 17352: // Proj_Map_Grid_of_Australia_52			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_52\012");
                      break;
                    case 17353: // Proj_Map_Grid_of_Australia_53			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_53\012");
                      break;
                    case 17354: // Proj_Map_Grid_of_Australia_54			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_54\012");
                      break;
                    case 17355: // Proj_Map_Grid_of_Australia_55			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_55\012");
                      break;
                    case 17356: // Proj_Map_Grid_of_Australia_56			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_56\012");
                      break;
                    case 17357: // Proj_Map_Grid_of_Australia_57			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_57\012");
                      break;
                    case 17358: // Proj_Map_Grid_of_Australia_58			
                      fprintf(file_out, "ProjectionGeoKey: Proj_Map_Grid_of_Australia_58\012");
                      break;
                    case 17448: // Proj_Australian_Map_Grid_48				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_48\012");
                      break;
                    case 17449: // Proj_Australian_Map_Grid_49				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_49\012");
                      break;
                    case 17450: // Proj_Australian_Map_Grid_50				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_50\012");
                      break;
                    case 17451: // Proj_Australian_Map_Grid_51				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_51\012");
                      break;
                    case 17452: // Proj_Australian_Map_Grid_52				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_52\012");
                      break;
                    case 17453: // Proj_Australian_Map_Grid_53				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_53\012");
                      break;
                    case 17454: // Proj_Australian_Map_Grid_54				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_54\012");
                      break;
                    case 17455: // Proj_Australian_Map_Grid_55				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_55\012");
                      break;
                    case 17456: // Proj_Australian_Map_Grid_56				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_56\012");
                      break;
                    case 17457: // Proj_Australian_Map_Grid_57				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_57\012");
                      break;
                    case 17458: // Proj_Australian_Map_Grid_58				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Australian_Map_Grid_58\012");
                      break;
                    case 18031: // Proj_Argentina_1					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Argentina_1\012");
                      break;
                    case 18032: // Proj_Argentina_2					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Argentina_2\012");
                      break;
                    case 18033: // Proj_Argentina_3					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Argentina_3\012");
                      break;
                    case 18034: // Proj_Argentina_4					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Argentina_4\012");
                      break;
                    case 18035: // Proj_Argentina_5					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Argentina_5\012");
                      break;
                    case 18036: // Proj_Argentina_6					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Argentina_6\012");
                      break;
                    case 18037: // Proj_Argentina_7					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Argentina_7\012");
                      break;
                    case 18051: // Proj_Colombia_3W					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Colombia_3W\012");
                      break;
                    case 18052: // Proj_Colombia_Bogota				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Colombia_Bogota\012");
                      break;
                    case 18053: // Proj_Colombia_3E					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Colombia_3E\012");
                      break;
                    case 18054: // Proj_Colombia_6E					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Colombia_6E\012");
                      break;
                    case 18072: // Proj_Egypt_Red_Belt					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Egypt_Red_Belt\012");
                      break;
                    case 18073: // Proj_Egypt_Purple_Belt				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Egypt_Purple_Belt\012");
                      break;
                    case 18074: // Proj_Extended_Purple_Belt				
                      fprintf(file_out, "ProjectionGeoKey: Proj_Extended_Purple_Belt\012");
                      break;
                    case 18141: // Proj_New_Zealand_North_Island_Nat_Grid		
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Zealand_North_Island_Nat_Grid\012");
                      break;
                    case 18142: // Proj_New_Zealand_South_Island_Nat_Grid		
                      fprintf(file_out, "ProjectionGeoKey: Proj_New_Zealand_South_Island_Nat_Grid\012");
                      break;
                    case 19900: // Proj_Bahrain_Grid					
                      fprintf(file_out, "ProjectionGeoKey: Proj_Bahrain_Grid\012");
                      break;
                    case 19905: // Proj_Netherlands_E_Indies_Equatorial		
                      fprintf(file_out, "ProjectionGeoKey: Proj_Netherlands_E_Indies_Equatorial\012");
                      break;
                    case 19912: // Proj_RSO_Borneo
                      fprintf(file_out, "ProjectionGeoKey: Proj_RSO_Borneo\012");
                      break;
                    default:
                      fprintf(file_out, "ProjectionGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  }
                  break;
                case 3075: // ProjCoordTransGeoKey
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 1: // CT_TransverseMercator
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_TransverseMercator\012");
                    break;
                  case 2: // CT_TransvMercator_Modified_Alaska
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_TransvMercator_Modified_Alaska\012");
                    break;
                  case 3: // CT_ObliqueMercator
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_ObliqueMercator\012");
                    break;
                  case 4: // CT_ObliqueMercator_Laborde
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_ObliqueMercator_Laborde\012");
                    break;
                  case 5: // CT_ObliqueMercator_Rosenmund
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_ObliqueMercator_Rosenmund\012");
                    break;
                  case 6: // CT_ObliqueMercator_Spherical
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_ObliqueMercator_Spherical\012");
                    break;
                  case 7: // CT_Mercator
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_Mercator\012");
                    break;
                  case 8: // CT_LambertConfConic_2SP
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_LambertConfConic_2SP\012");
                    break;
                  case 9: // CT_LambertConfConic_Helmert
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_LambertConfConic_Helmert\012");
                    break;
                  case 10: // CT_LambertAzimEqualArea
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_LambertAzimEqualArea\012");
                    break;
                  case 11: // CT_AlbersEqualArea
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_AlbersEqualArea\012");
                    break;
                  case 12: // CT_AzimuthalEquidistant
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_AzimuthalEquidistant\012");
                    break;
                  case 13: // CT_EquidistantConic
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_EquidistantConic\012");
                    break;
                  case 14: // CT_Stereographic
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_Stereographic\012");
                    break;
                  case 15: // CT_PolarStereographic
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_PolarStereographic\012");
                    break;
                  case 16: // CT_ObliqueStereographic
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_ObliqueStereographic\012");
                    break;
                  case 17: // CT_Equirectangular
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_Equirectangular\012");
                    break;
                  case 18: // CT_CassiniSoldner
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_CassiniSoldner\012");
                    break;
                  case 19: // CT_Gnomonic
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_Gnomonic\012");
                    break;
                  case 20: // CT_MillerCylindrical
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_MillerCylindrical\012");
                    break;
                  case 21: // CT_Orthographic
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_Orthographic\012");
                    break;
                  case 22: // CT_Polyconic
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_Polyconic\012");
                    break;
                  case 23: // CT_Robinson
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_Robinson\012");
                    break;
                  case 24: // CT_Sinusoidal
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_Sinusoidal\012");
                    break;
                  case 25: // CT_VanDerGrinten
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_VanDerGrinten\012");
                    break;
                  case 26: // CT_NewZealandMapGrid
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_NewZealandMapGrid\012");
                    break;
                  case 27: // CT_TransvMercator_SouthOriented
                    fprintf(file_out, "ProjCoordTransGeoKey: CT_TransvMercator_SouthOriented\012");
                    break;
                  default:
                    fprintf(file_out, "ProjCoordTransGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 3076: // ProjLinearUnitsGeoKey
                  horizontal_units = lasreader->header.vlr_geo_key_entries[j].value_offset;
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 9001: // Linear_Meter
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Meter\012");
                    break;
                  case 9002: // Linear_Foot
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Foot\012");
                    break;
                  case 9003: // Linear_Foot_US_Survey
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Foot_US_Survey\012");
                    break;
                  case 9004: // Linear_Foot_Modified_American
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Foot_Modified_American\012");
                    break;
                  case 9005: // Linear_Foot_Clarke
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Foot_Clarke\012");
                    break;
                  case 9006: // Linear_Foot_Indian
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Foot_Indian\012");
                    break;
                  case 9007: // Linear_Link
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Link\012");
                    break;
                  case 9008: // Linear_Link_Benoit
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Link_Benoit\012");
                    break;
                  case 9009: // Linear_Link_Sears
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Link_Sears\012");
                    break;
                  case 9010: // Linear_Chain_Benoit
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Chain_Benoit\012");
                    break;
                  case 9011: // Linear_Chain_Sears
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Chain_Sears\012");
                    break;
                  case 9012: // Linear_Yard_Sears
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Yard_Sears\012");
                    break;
                  case 9013: // Linear_Yard_Indian
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Yard_Indian\012");
                    break;
                  case 9014: // Linear_Fathom
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Fathom\012");
                    break;
                  case 9015: // Linear_Mile_International_Nautical
                    fprintf(file_out, "ProjLinearUnitsGeoKey: Linear_Mile_International_Nautical\012");
                    break;
                  default:
                    fprintf(file_out, "ProjLinearUnitsGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 3077: // ProjLinearUnitSizeGeoKey
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjLinearUnitSizeGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3078: // ProjStdParallel1GeoKey
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjStdParallel1GeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3079: // ProjStdParallel2GeoKey
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjStdParallel2GeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;        
                case 3080: // ProjNatOriginLongGeoKey
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjNatOriginLongGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3081: // ProjNatOriginLatGeoKey
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjNatOriginLatGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3082: // ProjFalseEastingGeoKey
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjFalseEastingGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3083: // ProjFalseNorthingGeoKey
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjFalseNorthingGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3084: // ProjFalseOriginLongGeoKey
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjFalseOriginLongGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3085: // ProjFalseOriginLatGeoKey
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjFalseOriginLatGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3086: // ProjFalseOriginEastingGeoKey
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjFalseOriginEastingGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3087: // ProjFalseOriginNorthingGeoKey
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjFalseOriginNorthingGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3088: // ProjCenterLongGeoKey
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjCenterLongGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3089: // ProjCenterLatGeoKey
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjCenterLatGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3090: // ProjCenterEastingGeoKey
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjCenterEastingGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3091: // ProjCenterNorthingGeoKey
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjCenterNorthingGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3092: // ProjScaleAtNatOriginGeoKey
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjScaleAtNatOriginGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3093: // ProjScaleAtCenterGeoKey
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjScaleAtCenterGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3094: // ProjAzimuthAngleGeoKey
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjAzimuthAngleGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 3095: // ProjStraightVertPoleLongGeoKey
                  if (lasreader->header.vlr_geo_double_params)
                  {
                    fprintf(file_out, "ProjStraightVertPoleLongGeoKey: %.10g\012",lasreader->header.vlr_geo_double_params[lasreader->header.vlr_geo_key_entries[j].value_offset]);
                  }
                  break;
                case 4096: // VerticalCSTypeGeoKey 
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 1127: // VertCS_Canadian_Geodetic_Vertical_Datum_2013
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Canadian_Geodetic_Vertical_Datum_2013\012");
                    break;
                  case 5001: // VertCS_Airy_1830_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Airy_1830_ellipsoid\012");
                    break;
                  case 5002: // VertCS_Airy_Modified_1849_ellipsoid 
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Airy_Modified_1849_ellipsoid\012");
                    break;
                  case 5003: // VertCS_ANS_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_ANS_ellipsoid\012");
                    break;
                  case 5004: // VertCS_Bessel_1841_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Bessel_1841_ellipsoid\012");
                    break;
                  case 5005: // VertCS_Bessel_Modified_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Bessel_Modified_ellipsoid\012");
                    break;
                  case 5006: // VertCS_Bessel_Namibia_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Bessel_Namibia_ellipsoid\012");
                    break;
                  case 5007: // VertCS_Clarke_1858_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Clarke_1858_ellipsoid\012");
                    break;
                  case 5008: // VertCS_Clarke_1866_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Clarke_1866_ellipsoid\012");
                    break;
                  case 5010: // VertCS_Clarke_1880_Benoit_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Clarke_1880_Benoit_ellipsoid\012");
                    break;
                  case 5011: // VertCS_Clarke_1880_IGN_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Clarke_1880_IGN_ellipsoid\012");
                    break;
                  case 5012: // VertCS_Clarke_1880_RGS_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Clarke_1880_RGS_ellipsoid\012");
                    break;
                  case 5013: // VertCS_Clarke_1880_Arc_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Clarke_1880_Arc_ellipsoid\012");
                    break;
                  case 5014: // VertCS_Clarke_1880_SGA_1922_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Clarke_1880_SGA_1922_ellipsoid\012");
                    break;
                  case 5015: // VertCS_Everest_1830_1937_Adjustment_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Everest_1830_1937_Adjustment_ellipsoid\012");
                    break;
                  case 5016: // VertCS_Everest_1830_1967_Definition_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Everest_1830_1967_Definition_ellipsoid\012");
                    break;
                  case 5017: // VertCS_Everest_1830_1975_Definition_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Everest_1830_1975_Definition_ellipsoid\012");
                    break;
                  case 5018: // VertCS_Everest_1830_Modified_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Everest_1830_Modified_ellipsoid\012");
                    break;
                  case 5019: // VertCS_GRS_1980_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_GRS_1980_ellipsoid\012");
                    break;
                  case 5020: // VertCS_Helmert_1906_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Helmert_1906_ellipsoid\012");
                    break;
                  case 5021: // VertCS_INS_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_INS_ellipsoid\012");
                    break;
                  case 5022: // VertCS_International_1924_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_International_1924_ellipsoid\012");
                    break;
                  case 5023: // VertCS_International_1967_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_International_1967_ellipsoid\012");
                    break;
                  case 5024: // VertCS_Krassowsky_1940_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Krassowsky_1940_ellipsoid\012");
                    break;
                  case 5025: // VertCS_NWL_9D_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_NWL_9D_ellipsoid\012");
                    break;
                  case 5026: // VertCS_NWL_10D_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_NWL_10D_ellipsoid\012");
                    break;
                  case 5027: // VertCS_Plessis_1817_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Plessis_1817_ellipsoid\012");
                    break;
                  case 5028: // VertCS_Struve_1860_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Struve_1860_ellipsoid\012");
                    break;
                  case 5029: // VertCS_War_Office_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_War_Office_ellipsoid\012");
                    break;
                  case 5030: // VertCS_WGS_84_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_WGS_84_ellipsoid\012");
                    break;
                  case 5031: // VertCS_GEM_10C_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_GEM_10C_ellipsoid\012");
                    break;
                  case 5032: // VertCS_OSU86F_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_OSU86F_ellipsoid\012");
                    break;
                  case 5033: // VertCS_OSU91A_ellipsoid
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_OSU91A_ellipsoid\012");
                    break;
                  case 5101: // VertCS_Newlyn
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Newlyn\012");
                    break;
                  case 5102: // VertCS_North_American_Vertical_Datum_1929
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_North_American_Vertical_Datum_1929\012");
                    break;
                  case 5103: // VertCS_North_American_Vertical_Datum_1988
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_North_American_Vertical_Datum_1988\012");
                    break;
                  case 5104: // VertCS_Yellow_Sea_1956
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Yellow_Sea_1956\012");
                    break;
                  case 5105: // VertCS_Baltic_Sea
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Baltic_Sea\012");
                    break;
                  case 5106: // VertCS_Caspian_Sea
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Caspian_Sea\012");
                    break;
                  case 5114: // VertCS_Canadian_Geodetic_Vertical_Datum_1928
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Canadian_Geodetic_Vertical_Datum_1928\012");
                    break;
                  case 5206: // VertCS_Dansk_Vertikal_Reference_1990
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_Dansk_Vertikal_Reference_1990\012");
                    break;
                  case 5215: // VertCS_European_Vertical_Reference_Frame_2007
                    fprintf(file_out, "VerticalCSTypeGeoKey: VertCS_European_Vertical_Reference_Frame_2007\012");
                    break;
                  case 5701: // ODN height (Reserved EPSG)
                    fprintf(file_out, "VerticalCSTypeGeoKey: ODN height (Reserved EPSG)\012");
                    break;
                  case 5702: // NGVD29 height (Reserved EPSG)
                    fprintf(file_out, "VerticalCSTypeGeoKey: NGVD29 height (Reserved EPSG)\012");
                    break;
                  case 5703: // NAVD88 height (Reserved EPSG)
                    fprintf(file_out, "VerticalCSTypeGeoKey: NAVD88 height (Reserved EPSG)\012");
                    break;
                  case 5704: // Yellow Sea (Reserved EPSG)
                    fprintf(file_out, "VerticalCSTypeGeoKey: Yellow Sea (Reserved EPSG)\012");
                    break;
                  case 5705: // Baltic height (Reserved EPSG)
                    fprintf(file_out, "VerticalCSTypeGeoKey: Baltic height (Reserved EPSG)\012");
                    break;
                  case 5706: // Caspian depth (Reserved EPSG)
                    fprintf(file_out, "VerticalCSTypeGeoKey: Caspian depth (Reserved EPSG)\012");
                    break;
                  case 5707: // NAP height (Reserved EPSG)
                    fprintf(file_out, "VerticalCSTypeGeoKey: NAP height (Reserved EPSG)\012");
                    break;
                  case 5710: // Oostende height (Reserved EPSG)
                    fprintf(file_out, "VerticalCSTypeGeoKey: Oostende height (Reserved EPSG)\012");
                    break;
                  case 5711: // AHD height (Reserved EPSG)
                    fprintf(file_out, "VerticalCSTypeGeoKey: AHD height (Reserved EPSG)\012");
                    break;
                  case 5712: // AHD (Tasmania) height (Reserved EPSG)
                    fprintf(file_out, "VerticalCSTypeGeoKey: AHD (Tasmania) height (Reserved EPSG)\012");
                    break;
                  case 5776: // Norway Normal Null 1954
                    fprintf(file_out, "VerticalCSTypeGeoKey: Norway Normal Null 1954\012");
                    break;
                  case 5783: // Deutches Haupthohennetz 1992
                    fprintf(file_out, "VerticalCSTypeGeoKey: Deutsches Haupthoehennetz 1992\012");
                    break;
                  case 5941: // Norway Normal Null 2000
                    fprintf(file_out, "VerticalCSTypeGeoKey: Norway Normal Null 2000\012");
                    break;
                  case 6647: // Norway Normal Null 2000
                    fprintf(file_out, "VerticalCSTypeGeoKey: Canadian Geodetic Vertical Datum of 2013\012");
                    break;
                  default:
                    fprintf(file_out, "VerticalCSTypeGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                case 4097: // VerticalCitationGeoKey
                  if (lasreader->header.vlr_geo_ascii_params)
                  {
                    char dummy[256];
                    strncpy(dummy, &(lasreader->header.vlr_geo_ascii_params[lasreader->header.vlr_geo_key_entries[j].value_offset]), lasreader->header.vlr_geo_key_entries[j].count);
                    dummy[lasreader->header.vlr_geo_key_entries[j].count-1] = '\0';
                    fprintf(file_out, "VerticalCitationGeoKey: %s\012",dummy);
                  }
                  break;
                case 4098: // VerticalDatumGeoKey 
                  fprintf(file_out, "VerticalDatumGeoKey: Vertical Datum Codes %d\012",lasreader->header.vlr_geo_key_entries[j].value_offset);
                  break;
                case 4099: // VerticalUnitsGeoKey 
                  switch (lasreader->header.vlr_geo_key_entries[j].value_offset)
                  {
                  case 9001: // Linear_Meter
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Meter\012");
                    break;
                  case 9002: // Linear_Foot
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Foot\012");
                    break;
                  case 9003: // Linear_Foot_US_Survey
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Foot_US_Survey\012");
                    break;
                  case 9004: // Linear_Foot_Modified_American
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Foot_Modified_American\012");
                    break;
                  case 9005: // Linear_Foot_Clarke
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Foot_Clarke\012");
                    break;
                  case 9006: // Linear_Foot_Indian
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Foot_Indian\012");
                    break;
                  case 9007: // Linear_Link
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Link\012");
                    break;
                  case 9008: // Linear_Link_Benoit
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Link_Benoit\012");
                    break;
                  case 9009: // Linear_Link_Sears
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Link_Sears\012");
                    break;
                  case 9010: // Linear_Chain_Benoit
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Chain_Benoit\012");
                    break;
                  case 9011: // Linear_Chain_Sears
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Chain_Sears\012");
                    break;
                  case 9012: // Linear_Yard_Sears
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Yard_Sears\012");
                    break;
                  case 9013: // Linear_Yard_Indian
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Yard_Indian\012");
                    break;
                  case 9014: // Linear_Fathom
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Fathom\012");
                    break;
                  case 9015: // Linear_Mile_International_Nautical
                    fprintf(file_out, "VerticalUnitsGeoKey: Linear_Mile_International_Nautical\012");
                    break;
                  default:
                    fprintf(file_out, "VerticalUnitsGeoKey: look-up for %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].value_offset);
                  }
                  break;
                default:
                  fprintf(file_out, "key ID %d not implemented\012", lasreader->header.vlr_geo_key_entries[j].key_id);
                }
              }
            }
          }
          else if (lasheader->vlrs[i].record_id == 34736) // GeoDoubleParamsTag
          {
            fprintf(file_out, "    GeoDoubleParamsTag (number of doubles %d)\012", lasreader->header.vlrs[i].record_length_after_header/8);
            fprintf(file_out, "      ");
            for (int j = 0; j < lasreader->header.vlrs[i].record_length_after_header/8; j++)
            {
              fprintf(file_out, "%lg ", lasheader->vlr_geo_double_params[j]);
            }
            fprintf(file_out, "\012");
          }
          else if (lasheader->vlrs[i].record_id == 34737) // GeoAsciiParamsTag
          {
            fprintf(file_out, "    GeoAsciiParamsTag (number of characters %d)\012", lasreader->header.vlrs[i].record_length_after_header);
            fprintf(file_out, "      ");
            for (int j = 0; j < lasreader->header.vlrs[i].record_length_after_header; j++)
            {
              if (lasheader->vlr_geo_ascii_params[j] >= ' ')
              {
                fprintf(file_out, "%c", lasheader->vlr_geo_ascii_params[j]);
              }
              else
              {
                fprintf(file_out, " ");
              }
            }
            fprintf(file_out, "\012");
          }
          else if (lasheader->vlrs[i].record_id == 2111) // WKT OGC MATH TRANSFORM
          {
            fprintf(file_out, "    WKT OGC MATH TRANSFORM:\012");
            fprintf(file_out, "    %s\012", lasreader->header.vlrs[i].data);
          }
          else if (lasheader->vlrs[i].record_id == 2112) // WKT OGC COORDINATE SYSTEM
          {
            fprintf(file_out, "    WKT OGC COORDINATE SYSTEM:\012");
            fprintf(file_out, "    %s\012", lasreader->header.vlrs[i].data);
          }
        }
        else if ((strcmp(lasheader->vlrs[i].user_id, "LASF_Spec") == 0) && (lasheader->vlrs[i].data != 0))
        {
          if (lasheader->vlrs[i].record_id == 0) // ClassificationLookup
          {
            LASvlr_classification* vlr_classification = (LASvlr_classification*)lasheader->vlrs[i].data;
            int num = lasheader->vlrs[i].record_length_after_header / sizeof(LASvlr_classification);
            for (int j = 0; j < num; j++)
            {
              fprintf(file_out, "    %d %.15s", vlr_classification[j].class_number, vlr_classification[j].description);
            }
            if (num) fprintf(file_out, "\012");
          }
          else if (lasheader->vlrs[i].record_id == 2) // Histogram
          {
          }
          else if (lasheader->vlrs[i].record_id == 3) // TextAreaDescription
          {
            fprintf(file_out, "    ");
            for (int j = 0; j < lasheader->vlrs[i].record_length_after_header; j++)
            {
              if (lasheader->vlrs[i].data[j] != '\0')
              {
                fprintf(file_out, "%c", lasheader->vlrs[i].data[j]);
              }
              else
              {
                fprintf(file_out, " ");
              }
            }
            fprintf(file_out, "\012");
          }
          else if (lasheader->vlrs[i].record_id == 4) // ExtraBytes
          {
            const char* name_table[10] = { "unsigned char", "char", "unsigned short", "short", "unsigned long", "long", "unsigned long long", "long long", "float", "double" };
            fprintf(file_out, "    Extra Byte Descriptions\012");
            for (int j = 0; j < lasheader->vlrs[i].record_length_after_header; j += 192)
            {
              if (lasheader->vlrs[i].data[j+2])
              {
                int type = ((I32)(lasheader->vlrs[i].data[j+2])-1)%10;
                int dim = ((I32)(lasheader->vlrs[i].data[j+2])-1)/10+1;
                if (file_out)
                {
                  fprintf(file_out, "      data type: %d (%s), name \"%s\", description: \"%s\"", (I32)(lasheader->vlrs[i].data[j+2]), name_table[type], (char*)(lasheader->vlrs[i].data + j + 4), (char*)(lasheader->vlrs[i].data + j + 160));
                  if (lasheader->vlrs[i].data[j+3] & 0x02) // if min is set
                  {
                    fprintf(file_out, ", min:");
                    for (int k = 0; k < dim; k++)
                    {
                      if (type < 8)
                      {
#ifdef _WIN32
                        fprintf(file_out, " %I64d", ((I64*)(lasheader->vlrs[i].data + j + 64))[k]);
#else
                        fprintf(file_out, ", %lld", ((I64*)(lasheader->vlrs[i].data + j + 64))[k]);
#endif
                      }
                      else
                      {
                        fprintf(file_out, " %g", ((F64*)(lasheader->vlrs[i].data + j + 64))[k]);
                      }
                    }
                  }
                  if (lasheader->vlrs[i].data[j+3] & 0x04) // if max is set
                  {
                    fprintf(file_out, ", max:");
                    for (int k = 0; k < dim; k++)
                    {
                      if (type < 8)
                      {
#ifdef _WIN32
                        fprintf(file_out, " %I64d", ((I64*)(lasheader->vlrs[i].data + j + 88))[k]);
#else
                        fprintf(file_out, ", %lld", ((I64*)(lasheader->vlrs[i].data + j + 88))[k]);
#endif
                      }
                      else
                      {
                        fprintf(file_out, " %g", ((F64*)(lasheader->vlrs[i].data + j + 88))[k]);
                      }
                    }
                  }
                  if (lasheader->vlrs[i].data[j+3] & 0x08) // if scale is set
                  {
                    fprintf(file_out, ", scale:");
                    for (int k = 0; k < dim; k++)
                    {
                      fprintf(file_out, " %g", ((F64*)(lasheader->vlrs[i].data + j + 112))[k]);
                    }
                  }
                  else
                  {
                    fprintf(file_out, ", scale: 1 (not set)");
                  }
                  if (lasheader->vlrs[i].data[j+3] & 0x10) // if offset is set
                  {
                    fprintf(file_out, ", offset:");
                    for (int k = 0; k < dim; k++)
                    {
                      fprintf(file_out, " %g", ((F64*)(lasheader->vlrs[i].data + j + 136))[k]);
                    }
                  }
                  else
                  {
                    fprintf(file_out, ", offset: 0 (not set)");
                  }
                  fprintf(file_out, "\012");
                }
              }
              else
              {
                fprintf(file_out, "      data type: 0 (untyped bytes), size: %d\012", lasheader->vlrs[i].data[j+3]);
              }
            }
          }
          else if ((lasheader->vlrs[i].record_id >= 100) && (lasheader->vlrs[i].record_id < 355)) // WavePacketDescriptor
          {
            LASvlr_wave_packet_descr* vlr_wave_packet_descr = (LASvlr_wave_packet_descr*)lasheader->vlrs[i].data;
            fprintf(file_out, "  index %d bits/sample %d compression %d samples %u temporal %u gain %lg, offset %lg\012", lasheader->vlrs[i].record_id-99, vlr_wave_packet_descr->getBitsPerSample(), vlr_wave_packet_descr->getCompressionType(), vlr_wave_packet_descr->getNumberOfSamples(), vlr_wave_packet_descr->getTemporalSpacing(), vlr_wave_packet_descr->getDigitizerGain(), vlr_wave_packet_descr->getDigitizerOffset());
          }
        }
      }
    }

    if (file_out && !no_variable_header)
    {
      for (int i = 0; i < (int)lasheader->number_of_extended_variable_length_records; i++)
      {
        fprintf(file_out, "extended variable length header record %d of %d:\012", i+1, (int)lasheader->number_of_extended_variable_length_records);
        fprintf(file_out, "  reserved             %d\012", lasreader->header.evlrs[i].reserved);
          fprintf(file_out, "  user ID              '%s'\012", lasreader->header.evlrs[i].user_id);
        fprintf(file_out, "  record ID            %d\012", lasreader->header.evlrs[i].record_id);
#ifdef _WIN32
        fprintf(file_out, "  length after header  %I64d\012", lasreader->header.evlrs[i].record_length_after_header);
#else
        fprintf(file_out, "  length after header  %lld\012", lasreader->header.evlrs[i].record_length_after_header);
#endif
          fprintf(file_out, "  description          '%s'\012", lasreader->header.evlrs[i].description);
        if (strcmp(lasheader->evlrs[i].user_id, "LASF_Projection") == 0)
        {
          if (lasheader->evlrs[i].record_id == 2111) // OGC MATH TRANSFORM WKT
          {
            fprintf(file_out, "    OGC MATH TRANSFORM WKT:\012");
            fprintf(file_out, "    %s\012", lasreader->header.evlrs[i].data);
          }
          else if (lasheader->evlrs[i].record_id == 2112) // OGC COORDINATE SYSTEM WKT
          {
            fprintf(file_out, "    OGC COORDINATE SYSTEM WKT:\012");
            fprintf(file_out, "    %s\012", lasreader->header.evlrs[i].data);
          }
        }
      }
    }

    if (file_out && !no_header)
    {
      if (lasheader->user_data_after_header_size) fprintf(file_out, "the header is followed by %u user-defined bytes\012", lasheader->user_data_after_header_size);

      if (lasheader->laszip)
      {
        fprintf(file_out, "LASzip compression (version %d.%dr%d c%d", lasheader->laszip->version_major, lasheader->laszip->version_minor, lasheader->laszip->version_revision, lasheader->laszip->compressor);
        if ((lasheader->laszip->compressor == LASZIP_COMPRESSOR_CHUNKED) || (lasheader->laszip->compressor == LASZIP_COMPRESSOR_LAYERED_CHUNKED)) fprintf(file_out, " %d):", lasheader->laszip->chunk_size);
        else fprintf(file_out, "):");
        for (i = 0; i < (int)lasheader->laszip->num_items; i++) fprintf(file_out, " %s %d", lasheader->laszip->items[i].get_name(), lasheader->laszip->items[i].version);
        fprintf(file_out, "\012");
      }
      if (lasheader->vlr_lastiling)
      {
        fprintf(file_out, "LAStiling (idx %d, lvl %d, sub %d, bbox %g %g %g %g%s%s)\n", 
          lasheader->vlr_lastiling->level_index, 
          lasheader->vlr_lastiling->level,
          lasheader->vlr_lastiling->implicit_levels,
          lasheader->vlr_lastiling->min_x,
          lasheader->vlr_lastiling->min_y,
          lasheader->vlr_lastiling->max_x,
          lasheader->vlr_lastiling->max_y,
          (lasheader->vlr_lastiling->buffer ? ", buffer" : ""),
          (lasheader->vlr_lastiling->reversible ? ", reversible" : ""));
      }
      if (lasheader->vlr_lasoriginal)
      {
        fprintf(file_out, "LASoriginal (npoints %u, bbox %g %g %g %g %g %g)\n", 
          (U32)lasheader->vlr_lasoriginal->number_of_point_records, 
          lasheader->vlr_lasoriginal->min_x,
          lasheader->vlr_lasoriginal->min_y,
          lasheader->vlr_lasoriginal->min_z,
          lasheader->vlr_lasoriginal->max_x,
          lasheader->vlr_lasoriginal->max_y,
          lasheader->vlr_lasoriginal->max_z);
      }
    }

    // loop over the points
    F64 enlarged_min_x = lasreader->header.min_x - 0.25 * lasreader->header.x_scale_factor;
    F64 enlarged_max_x = lasreader->header.max_x + 0.25 * lasreader->header.x_scale_factor;
    F64 enlarged_min_y = lasreader->header.min_y - 0.25 * lasreader->header.y_scale_factor;
    F64 enlarged_max_y = lasreader->header.max_y + 0.25 * lasreader->header.y_scale_factor;
    F64 enlarged_min_z = lasreader->header.min_z - 0.25 * lasreader->header.z_scale_factor;
    F64 enlarged_max_z = lasreader->header.max_z + 0.25 * lasreader->header.z_scale_factor;
    LASsummary lassummary;

    if (check_points)
    {
      I64 num_first_returns = 0;
      I64 num_intermediate_returns = 0;
      I64 num_last_returns = 0;
      I64 num_single_returns = 0;
      I64 num_all_returns = 0;
      I64 outside_bounding_box = 0;
      LASoccupancyGrid* lasoccupancygrid = 0;

      if (compute_density)
      {
        lasoccupancygrid = new LASoccupancyGrid(horizontal_units > 9001 ? 6.0f : 2.0f);
      }

      if (file_out && !no_min_max) fprintf(file_out, "reporting minimum and maximum for all LAS point record entries ...\012");

      // maybe seek to start position

      if (subsequence_start) lasreader->seek(subsequence_start);

      while (lasreader->read_point())
      {
        if (lasreader->p_count > subsequence_stop) break;

        if (check_outside)
        {
          if (!lasreader->point.inside_bounding_box(enlarged_min_x, enlarged_min_y, enlarged_min_z, enlarged_max_x, enlarged_max_y, enlarged_max_z))
          {
            outside_bounding_box++;
            if (file_out && report_outside)
            {
              fprintf(file_out, "%u t %g x %g y %g z %g i %d (%d of %d) d %d e %d c %d s %d %u p %d \012", (U32)(lasreader->p_count-1), lasreader->point.get_gps_time(), lasreader->point.get_x(), lasreader->point.get_y(), lasreader->point.get_z(), lasreader->point.get_intensity(), lasreader->point.get_return_number(), lasreader->point.get_number_of_returns(), lasreader->point.get_scan_direction_flag(), lasreader->point.get_edge_of_flight_line(), lasreader->point.get_classification(), lasreader->point.get_scan_angle_rank(), lasreader->point.get_user_data(), lasreader->point.get_point_source_ID());
            }
          }
        }

        lassummary.add(&lasreader->point);

        if (lasoccupancygrid)
        {
          lasoccupancygrid->add(&lasreader->point);
        }

        if (lasreader->point.is_first())
        {
          num_first_returns++;
        }
        if (lasreader->point.is_intermediate())
        {
          num_intermediate_returns++;
        }
        if (lasreader->point.is_last())
        {
          num_last_returns++;
        }
        if (lasreader->point.is_single())
        {
          num_single_returns++;
        }
        num_all_returns++;

        if (lashistogram.active())
        {
          lashistogram.add(&lasreader->point);
        }

#ifdef _WIN32
          if (file_out && progress && (lasreader->p_count % progress) == 0)
          {
            fprintf(file_out, " ... processed %I64d points ...\012", lasreader->p_count);
          }
#else
          if (file_out && progress && (lasreader->p_count % progress) == 0) {
              fprintf(file_out, " ... processed %lld points ...\012", lasreader->p_count);
          }
#endif
      }
      if (file_out && !no_min_max)
      {
        fprintf(file_out, "  X          %10d %10d\012",lassummary.min.get_X(), lassummary.max.get_X());
        fprintf(file_out, "  Y          %10d %10d\012",lassummary.min.get_Y(), lassummary.max.get_Y());
        fprintf(file_out, "  Z          %10d %10d\012",lassummary.min.get_Z(), lassummary.max.get_Z());
        fprintf(file_out, "  intensity  %10d %10d\012",lassummary.min.intensity, lassummary.max.intensity);
        fprintf(file_out, "  return_number       %d %10d\012",lassummary.min.return_number, lassummary.max.return_number);
        fprintf(file_out, "  number_of_returns   %d %10d\012",lassummary.min.number_of_returns, lassummary.max.number_of_returns);
        fprintf(file_out, "  edge_of_flight_line %d %10d\012",lassummary.min.edge_of_flight_line, lassummary.max.edge_of_flight_line);
        fprintf(file_out, "  scan_direction_flag %d %10d\012",lassummary.min.scan_direction_flag, lassummary.max.scan_direction_flag);
        fprintf(file_out, "  classification  %5d %10d\012",lassummary.min.classification, lassummary.max.classification);
        fprintf(file_out, "  scan_angle_rank %5d %10d\012",lassummary.min.scan_angle_rank, lassummary.max.scan_angle_rank);
        fprintf(file_out, "  user_data       %5d %10d\012",lassummary.min.user_data, lassummary.max.user_data);
        fprintf(file_out, "  point_source_ID %5d %10d\012",lassummary.min.point_source_ID, lassummary.max.point_source_ID);
        if (lasreader->point.have_gps_time)
        {
          fprintf(file_out, "  gps_time %f %f\012",lassummary.min.gps_time, lassummary.max.gps_time);
          if ((lasreader->header.global_encoding & 1) == 0)
          {
            if (!no_warnings && (lassummary.min.gps_time < 0.0 || lassummary.max.gps_time > 604800.0))
            {
              fprintf(file_out, "WARNING: range violates GPS week time specified by global encoding bit 0\012");
            }
          }
          else if (gps_week)
          {
            I32 week_min = (I32)(lassummary.min.gps_time/604800.0 + 1653.4391534391534391534391534392);
            I32 week_max = (I32)(lassummary.max.gps_time/604800.0 + 1653.4391534391534391534391534392);
            I32 secs_min = week_min*604800 - 1000000000;
            I32 secs_max = week_max*604800 - 1000000000;
            fprintf(file_out, "  gps_week %d %d\012", week_min, week_max);
            fprintf(file_out, "  gps_secs_of_week %f %f\012", (lassummary.min.gps_time-secs_min), (lassummary.max.gps_time-secs_max));
          }
        }
        if (lasreader->point.have_rgb)
        {
          fprintf(file_out, "  Color R %d %d\012", lassummary.min.rgb[0], lassummary.max.rgb[0]);
          fprintf(file_out, "        G %d %d\012", lassummary.min.rgb[1], lassummary.max.rgb[1]);
          fprintf(file_out, "        B %d %d\012", lassummary.min.rgb[2], lassummary.max.rgb[2]);
        }
        if (lasreader->point.have_nir)
        {
          fprintf(file_out, "      NIR %d %d\012", lassummary.min.rgb[3], lassummary.max.rgb[3]);
        }
        if (lasreader->point.have_wavepacket)
        {
          fprintf(file_out, "  Wavepacket Index    %d %d\012", lassummary.min.wavepacket.getIndex(), lassummary.max.wavepacket.getIndex());
#ifdef _WIN32
          fprintf(file_out, "             Offset   %I64d %I64d\012", lassummary.min.wavepacket.getOffset(), lassummary.max.wavepacket.getOffset());
#else
          fprintf(file_out, "             Offset   %lld %lld\012", lassummary.min.wavepacket.getOffset(), lassummary.max.wavepacket.getOffset());
#endif
          fprintf(file_out, "             Size     %d %d\012", lassummary.min.wavepacket.getSize(), lassummary.max.wavepacket.getSize());
          fprintf(file_out, "             Location %g %g\012", lassummary.min.wavepacket.getLocation(), lassummary.max.wavepacket.getLocation());
          fprintf(file_out, "             Xt       %g %g\012", lassummary.min.wavepacket.getXt(), lassummary.max.wavepacket.getXt());
          fprintf(file_out, "             Yt       %g %g\012", lassummary.min.wavepacket.getYt(), lassummary.max.wavepacket.getYt());
          fprintf(file_out, "             Zt       %g %g\012", lassummary.min.wavepacket.getZt(), lassummary.max.wavepacket.getZt());
        }
        if (lasreader->point.extended_point_type)
        {
          fprintf(file_out, "  extended_return_number     %6d %6d\012", lassummary.min.extended_return_number, lassummary.max.extended_return_number);
          fprintf(file_out, "  extended_number_of_returns %6d %6d\012", lassummary.min.extended_number_of_returns, lassummary.max.extended_number_of_returns);
          fprintf(file_out, "  extended_classification    %6d %6d\012", lassummary.min.extended_classification, lassummary.max.extended_classification);
          fprintf(file_out, "  extended_scan_angle        %6d %6d\012", lassummary.min.extended_scan_angle, lassummary.max.extended_scan_angle);
          fprintf(file_out, "  extended_scanner_channel   %6d %6d\012", lassummary.min.extended_scanner_channel, lassummary.max.extended_scanner_channel);
        }
        if (lasreader->point.extra_bytes_number && lasreader->point.attributer)
        {
          lassummary.min.attributer = lasreader->point.attributer;
          lassummary.max.attributer = lasreader->point.attributer;
          I32 a;
          for (a = 0; a < lasreader->point.attributer->number_attributes; a++)
          {
            fprintf(file_out, "  attribute%d %10g %10g  ('%s')\012", a, lassummary.min.get_attribute_as_float(a), lassummary.max.get_attribute_as_float(a), lasreader->point.attributer->get_attribute_name(a));
          }
          lassummary.min.attributer = 0;
          lassummary.max.attributer = 0;
        }
        if (((number_of_point_records == 0) && (lasheader->number_of_point_records > 0)) || ((number_of_points_by_return0 == 0) && (lasheader->number_of_points_by_return[0] > 0)))
        {
          fprintf(file_out, "re-reporting LAS header entries populated during read pass:\012");
          if ((number_of_point_records == 0) && (lasheader->number_of_point_records > 0)) fprintf(file_out, "  number of point records    %u\012", lasheader->number_of_point_records);
          if ((number_of_points_by_return0 == 0) && (lasheader->number_of_points_by_return[0] > 0)) fprintf(file_out, "  number of points by return %u %u %u %u %u\012", lasheader->number_of_points_by_return[0], lasheader->number_of_points_by_return[1], lasheader->number_of_points_by_return[2], lasheader->number_of_points_by_return[3], lasheader->number_of_points_by_return[4]);
          fprintf(file_out, "  min x y z                  "); lidardouble2string(printstring, lasheader->min_x, lasheader->x_scale_factor); fprintf(file_out, "%s ", printstring); lidardouble2string(printstring, lasheader->min_y, lasheader->y_scale_factor); fprintf(file_out, "%s ", printstring); lidardouble2string(printstring, lasheader->min_z, lasheader->z_scale_factor); fprintf(file_out, "%s\012", printstring);
          fprintf(file_out, "  max x y z                  "); lidardouble2string(printstring, lasheader->max_x, lasheader->x_scale_factor); fprintf(file_out, "%s ", printstring); lidardouble2string(printstring, lasheader->max_y, lasheader->y_scale_factor); fprintf(file_out, "%s ", printstring); lidardouble2string(printstring, lasheader->max_z, lasheader->z_scale_factor); fprintf(file_out, "%s\012", printstring);
        }
      }
      if (!no_warnings && file_out && outside_bounding_box)
      {
#ifdef _WIN32
        fprintf(file_out, "WARNING: %I64d points outside of header bounding box\012", outside_bounding_box);
#else
        fprintf(file_out, "WARNING: %lld points outside of header bounding box\012", outside_bounding_box);
#endif
      }
      if (!no_warnings && file_out && lassummary.has_fluff())
      {
        fprintf(file_out, "WARNING: there is coordinate resolution fluff (x10) in %s%s%s\012", (lassummary.has_fluff(0) ? "X" : ""), (lassummary.has_fluff(1) ? "Y" : ""), (lassummary.has_fluff(2) ? "Z" : ""));
        if (lassummary.has_serious_fluff())
        {
          fprintf(file_out, "WARNING: there is serious coordinate resolution fluff (x100) in %s%s%s\012", (lassummary.has_serious_fluff(0) ? "X" : ""), (lassummary.has_serious_fluff(1) ? "Y" : ""), (lassummary.has_serious_fluff(2) ? "Z" : ""));
          if (lassummary.has_very_serious_fluff())
          {
            fprintf(file_out, "WARNING: there is very serious coordinate resolution fluff (x1000) in %s%s%s\012", (lassummary.has_very_serious_fluff(0) ? "X" : ""), (lassummary.has_very_serious_fluff(1) ? "Y" : ""), (lassummary.has_very_serious_fluff(2) ? "Z" : ""));
            if (lassummary.has_extremely_serious_fluff())
            {
              fprintf(file_out, "WARNING: there is extremely serious coordinate resolution fluff (x10000) in %s%s%s\012", (lassummary.has_extremely_serious_fluff(0) ? "X" : ""), (lassummary.has_extremely_serious_fluff(1) ? "Y" : ""), (lassummary.has_extremely_serious_fluff(2) ? "Z" : ""));
            }
          }
        }
      }
      if (file_out && !no_returns)
      {
#ifdef _WIN32
        fprintf(file_out, "number of first returns:        %I64d\012", num_first_returns);
        fprintf(file_out, "number of intermediate returns: %I64d\012", num_intermediate_returns);
        fprintf(file_out, "number of last returns:         %I64d\012", num_last_returns);
        fprintf(file_out, "number of single returns:       %I64d\012", num_single_returns);
#else
        fprintf(file_out, "number of first returns:        %lld\012", num_first_returns);
        fprintf(file_out, "number of intermediate returns: %lld\012", num_intermediate_returns);
        fprintf(file_out, "number of last returns:         %lld\012", num_last_returns);
        fprintf(file_out, "number of single returns:       %lld\012", num_single_returns);
#endif
      }
      if (file_out && lasoccupancygrid)
      {
        if (num_last_returns)
        {
          if (horizontal_units == 9001)
          {
            fprintf(file_out, "covered area in square meters/kilometers: %d/%.2f\012", 4*lasoccupancygrid->get_num_occupied(), 0.000004*lasoccupancygrid->get_num_occupied());
            fprintf(file_out, "point density: all returns %.2f last only %.2f (per square meter)\012", ((F64)num_all_returns/(4.0*lasoccupancygrid->get_num_occupied())), ((F64)num_last_returns/(4.0*lasoccupancygrid->get_num_occupied())));
            fprintf(file_out, "      spacing: all returns %.2f last only %.2f (in meters)\012", sqrt(4.0*lasoccupancygrid->get_num_occupied()/(F64)num_all_returns), sqrt(4.0*lasoccupancygrid->get_num_occupied()/(F64)num_last_returns));
          }
          else if (horizontal_units == 9002)
          {
            fprintf(file_out, "covered area in square feet/miles: %d/%.2f\012", 36*lasoccupancygrid->get_num_occupied(),1.2913223e-6*lasoccupancygrid->get_num_occupied());
            fprintf(file_out, "point density: all returns %.2f last only %.2f (per square foot)\012", ((F64)num_all_returns/(36.0*lasoccupancygrid->get_num_occupied())), ((F64)num_last_returns/(36.0*lasoccupancygrid->get_num_occupied())));
            fprintf(file_out, "      spacing: all returns %.2f last only %.2f (in feet)\012", sqrt(36.0*lasoccupancygrid->get_num_occupied()/(F64)num_all_returns), sqrt(36.0*lasoccupancygrid->get_num_occupied()/(F64)num_last_returns));
          }
          else if (horizontal_units == 9003)
          {
            fprintf(file_out, "covered area in square survey feet: %d\012", 36*lasoccupancygrid->get_num_occupied());
            fprintf(file_out, "point density: all returns %.2f last only %.2f (per square survey foot)\012", ((F64)num_all_returns/(36.0*lasoccupancygrid->get_num_occupied())), ((F64)num_last_returns/(36.0*lasoccupancygrid->get_num_occupied())));
            fprintf(file_out, "      spacing: all returns %.2f last only %.2f (in survey feet)\012", sqrt(36.0*lasoccupancygrid->get_num_occupied()/(F64)num_all_returns), sqrt(36.0*lasoccupancygrid->get_num_occupied()/(F64)num_last_returns));
          }
          else
          {
            fprintf(file_out, "covered area in square units/kilounits: %d/%.2f\012", 4*lasoccupancygrid->get_num_occupied(), 0.000004*lasoccupancygrid->get_num_occupied());
            fprintf(file_out, "point density: all returns %.2f last only %.2f (per square units)\012", ((F64)num_all_returns/(4.0*lasoccupancygrid->get_num_occupied())), ((F64)num_last_returns/(4.0*lasoccupancygrid->get_num_occupied())));
            fprintf(file_out, "      spacing: all returns %.2f last only %.2f (in units)\012", sqrt(4.0*lasoccupancygrid->get_num_occupied()/(F64)num_all_returns), sqrt(4.0*lasoccupancygrid->get_num_occupied()/(F64)num_last_returns));
          }
        }
        delete lasoccupancygrid;
      }
    }

    lasreader->close();

    FILE* file = 0;

    if (repair_bb || repair_counters)
    {
      if (lasreadopener.is_piped())
      {
        fprintf(stderr, "ERROR: cannot repair header of piped input\n");
        repair_bb = repair_counters = false;
      }
      else if (lasreadopener.is_merged())
      {
        fprintf(stderr, "ERROR: cannot repair header of merged input\n");
        repair_bb = repair_counters = false;
      }
      else if (lasreadopener.is_buffered())
      {
        fprintf(stderr, "ERROR: cannot repair header of buffered input\n");
        repair_bb = repair_counters = false;
      }
      else if (lasreader->get_format() > LAS_TOOLS_FORMAT_LAZ)
      {
        fprintf(stderr, "ERROR: can only repair header for LAS or LAZ files, not for '%s'\n", lasreadopener.get_file_name());
        repair_bb = repair_counters = false;
      }
      file = fopen(lasreadopener.get_file_name(), "rb+");
      if (file == 0)
      {
        fprintf (stderr, "ERROR: could not reopen file '%s' for repair of header\n", lasreadopener.get_file_name());
        repair_bb = repair_counters = false;
      }
    }

    if (check_points)
    {
      // check number_of_point_records

      if ((lasheader->point_data_format < 6) && (lassummary.number_of_point_records != lasheader->number_of_point_records))
      {
        if (repair_counters)
        {
          if (lassummary.number_of_point_records <= U32_MAX)
          {
            U32 number_of_point_records = (U32)lassummary.number_of_point_records;;
            fseek(file, 107, SEEK_SET);
            fwrite(&number_of_point_records, sizeof(U32), 1, file);
            if (file_out)
            {
              fprintf(file_out, "WARNING: real number of point records (%u) is different from header entry (%u). it was repaired. \n", number_of_point_records, lasheader->number_of_point_records);
            }
          }
          else if (lasheader->version_minor < 4)
          {
            if (file_out)
            {
#ifdef _WIN32
              fprintf(file_out, "WARNING: real number of point records (%I64d) exceeds 4,294,967,295. cannot repair. too big.\n", lassummary.number_of_point_records);
#else
              fprintf(file_out, "WARNING: real number of point records (%lld) exceeds 4,294,967,295. cannot repair. too big.\n", lassummary.number_of_point_records);
#endif
            }
          }
          else if (lasheader->number_of_point_records != 0)
          {
            U32 number_of_point_records = 0;
            fseek(file, 107, SEEK_SET);
            fwrite(&number_of_point_records, sizeof(U32), 1, file);
            if (file_out)
            {
#ifdef _WIN32
              fprintf(file_out, "WARNING: real number of point records (%I64d) exceeds 4,294,967,295. but header entry is %u instead zero. it was repaired.\n", lassummary.number_of_point_records, lasheader->number_of_point_records);
#else
              fprintf(file_out, "WARNING: real number of point records (%lld) exceeds 4,294,967,295. but header entry is %u instead zero. it was repaired.\n", lassummary.number_of_point_records, lasheader->number_of_point_records);
#endif
            }
          }
          else
          {
            if (file_out)
            {
              fprintf(file_out, "number of point records in header is correct.\n");
            }
          }
        }
        else
        {
          if (!no_warnings && file_out)
          {
            if (lassummary.number_of_point_records <= U32_MAX)
            {
#ifdef _WIN32
              fprintf(file_out, "WARNING: real number of point records (%I64d) is different from header entry (%u).\n", lassummary.number_of_point_records, lasheader->number_of_point_records);
#else
              fprintf(file_out, "WARNING: real number of point records (%lld) is different from header entry (%u).\n", lassummary.number_of_point_records, lasheader->number_of_point_records);
#endif
            }
            else if (lasheader->version_minor < 4)
            {
#ifdef _WIN32
              fprintf(file_out, "WARNING: real number of point records (%I64d) exceeds 4,294,967,295.\n", lassummary.number_of_point_records);
#else
              fprintf(file_out, "WARNING: real number of point records (%lld) exceeds 4,294,967,295.\n", lassummary.number_of_point_records);
#endif
            }
            else if (lasheader->number_of_point_records != 0)
            {
#ifdef _WIN32
              fprintf(file_out, "WARNING: real number of point records (%I64d) exceeds 4,294,967,295. but header entry is %u instead of zero.\n", lassummary.number_of_point_records, lasheader->number_of_point_records);
#else
              fprintf(file_out, "WARNING: real number of point records (%lld) exceeds 4,294,967,295. but header entry is %u instead of zero.\n", lassummary.number_of_point_records, lasheader->number_of_point_records);
#endif
            }
          }
        }
      }
      else if ((lasheader->point_data_format >= 6) && (lasheader->number_of_point_records != 0))
      {
        if (repair_counters)
        {
          U32 number_of_point_records = 0;
          fseek(file, 107, SEEK_SET);
          fwrite(&number_of_point_records, sizeof(U32), 1, file);
        }
        if (!no_warnings && file_out)
        {
          fprintf(file_out, "WARNING: point type is %d but (legacy) number of point records in header is %u instead zero.%s\n", lasheader->point_data_format, lasheader->number_of_point_records, (repair_counters ? "it was repaired." : ""));
        }
      }
      else
      {
        if (repair_counters)
        {
          if (file_out)
          {
            fprintf(file_out, "number of point records in header is correct.\n");
          }
        }
      }

      // check extended_number_of_point_records

      if (lasheader->version_minor > 3)
      {
        if (lassummary.number_of_point_records != (I64)lasheader->extended_number_of_point_records)
        {
          if (repair_counters)
          {
            I64 extended_number_of_point_records = lassummary.number_of_point_records;
            fseek(file, 235 + 12, SEEK_SET);
            fwrite(&extended_number_of_point_records, sizeof(I64), 1, file);
          }
          if (!no_warnings && file_out)
          {
#ifdef _WIN32
            fprintf(file_out, "WARNING: real number of point records (%I64d) is different from extended header entry (%I64d).%s\n", lassummary.number_of_point_records, lasheader->extended_number_of_point_records, (repair_counters ? " it was repaired." : ""));
#else
            fprintf(file_out, "WARNING: real number of point records (%lld) is different from extended header entry (%lld).%s\n", lassummary.number_of_point_records, lasheader->extended_number_of_point_records, (repair_counters ? " it was repaired." : ""));
#endif
          }
        }
        else
        {
          if (repair_counters)
          {
            if (file_out)
            {
              fprintf(file_out, "extended number of point records in header is correct.\n");
            }
          }
        }
      }

      // check number_of_points_by_return[5]

      bool was_set = false;
      for (i = 1; i < 6; i++) if (lasheader->number_of_points_by_return[i-1]) was_set = true;

      bool wrong_entry = false;

      U32 number_of_points_by_return[5];
      for (i = 1; i < 6; i++)
      {
        if ((lasheader->point_data_format < 6) && ((I64)(lasheader->number_of_points_by_return[i-1]) != lassummary.number_of_points_by_return[i]))
        {
          if (lassummary.number_of_points_by_return[i] <= U32_MAX)
          {
            number_of_points_by_return[i-1] = (U32)lassummary.number_of_points_by_return[i];
            wrong_entry = true;
            if (!no_warnings && file_out)
            {
              if (was_set)
              {
                fprintf(file_out, "WARNING: for return %d real number of points by return (%u) is different from header entry (%u).%s\n", i, number_of_points_by_return[i-1], lasheader->number_of_points_by_return[i-1], (repair_counters ? " it was repaired." : ""));
              }
              else
              {
                fprintf(file_out, "WARNING: for return %d real number of points by return is %u but header entry was not set.%s\n", i, number_of_points_by_return[i-1], (repair_counters ? " it was repaired." : ""));
              }
            }
          }
          else if (lasheader->version_minor < 4)
          {
            if (!no_warnings && file_out)
            {
#ifdef _WIN32
              fprintf(file_out, "WARNING: for return %d real number of points by return (%I64d) exceeds 4,294,967,295.%s\n", i, lassummary.number_of_points_by_return[i], (repair_counters ? " cannot repair. too big." : ""));
#else
              fprintf(file_out, "WARNING: for return %d real number of points by return (%lld) exceeds 4,294,967,295.%s\n", i, lassummary.number_of_points_by_return[i], (repair_counters ? " cannot repair. too big." : ""));
#endif
            }
          }
          else if (lasheader->number_of_points_by_return[i-1] != 0)
          {
            number_of_points_by_return[i-1] = 0;
            wrong_entry = true;
            if (!no_warnings && file_out)
            {
#ifdef _WIN32
              fprintf(file_out, "WARNING: for return %d real number of points by return (%I64d) exceeds 4,294,967,295. but header entry is %u instead zero.%s\n", i, lassummary.number_of_points_by_return[i], lasheader->number_of_points_by_return[i-1], (repair_counters ? " it was repaired." : ""));
#else
              fprintf(file_out, "WARNING: for return %d real number of points by return (%lld) exceeds 4,294,967,295. but header entry is %u instead zero.%s\n", i, lassummary.number_of_points_by_return[i], lasheader->number_of_points_by_return[i-1], (repair_counters ? " it was repaired." : ""));
#endif
            }
          }
          else
          {
            number_of_points_by_return[i-1] = 0;
          }
        }
        else if ((lasheader->point_data_format >= 6) && (lasheader->number_of_points_by_return[i-1] != 0))
        {
          number_of_points_by_return[i-1] = 0;
          wrong_entry = true;
          if (!no_warnings && file_out)
          {
            fprintf(file_out, "WARNING: point type is %d but (legacy) number of points by return [%d] in header is %u instead zero.%s\n", lasheader->point_data_format, i, lasheader->number_of_points_by_return[i-1], (repair_counters ? "it was repaired." : ""));
          }
        }
        else
        {
          number_of_points_by_return[i-1] = (U32)lassummary.number_of_points_by_return[i];
        }
      }

      if (repair_counters)
      {
        if (wrong_entry)
        {
          fseek(file, 111, SEEK_SET);
          fwrite(&(number_of_points_by_return[0]), sizeof(U32), 5, file);
        }
        else if (file_out)
        {
          fprintf(file_out, "number of points by return in header is correct.\n");
        }
      }
      
      // check extended_number_of_points_by_return[15]

      if (lasheader->version_minor > 3)
      {
        bool was_set = false;
        for (i = 1; i < 15; i++) if (lasheader->extended_number_of_points_by_return[i-1]) was_set = true;

        bool wrong_entry = false;

        I64 extended_number_of_points_by_return[15];

        for (i = 1; i < 16; i++)
        {
          extended_number_of_points_by_return[i-1] = lassummary.number_of_points_by_return[i];
          if ((I64)lasheader->extended_number_of_points_by_return[i-1] != lassummary.number_of_points_by_return[i])
          {
            wrong_entry = true;
            if (!no_warnings && file_out)
            {
              if (was_set)
              {
#ifdef _WIN32
                fprintf(file_out, "WARNING: real extended number of points by return [%d] is %I64d - different from header entry %I64d.%s\n", i, lassummary.number_of_points_by_return[i], lasheader->extended_number_of_points_by_return[i-1], (repair_counters ? " it was repaired." : ""));
#else
                fprintf(file_out, "WARNING: real extended number of points by return [%d] is %lld - different from header entry %lld.%s\n", i, lassummary.number_of_points_by_return[i], lasheader->extended_number_of_points_by_return[i-1], (repair_counters ? " it was repaired." : ""));
#endif
              }
              else
              {
#ifdef _WIN32
                fprintf(file_out, "WARNING: real extended number of points by return [%d] is %I64d but header entry was not set.%s\n", i, lassummary.number_of_points_by_return[i], (repair_counters ? " it was repaired." : ""));
#else
                fprintf(file_out, "WARNING: real extended number of points by return [%d] is %lld but header entry was not set.%s\n", i, lassummary.number_of_points_by_return[i], (repair_counters ? " it was repaired." : ""));
#endif
              }
            }
          }
        }

        if (repair_counters)
        {
          if (wrong_entry)
          {
            fseek(file, 235 + 20, SEEK_SET);
            fwrite(&(extended_number_of_points_by_return[0]), sizeof(I64), 15, file);
          }
          else if (file_out)
          {
            fprintf(file_out, "extended number of points by return in header is correct.\n");
          }
        }
      }

      if (!no_warnings && file_out && !no_returns)
      {
#ifdef _WIN32
        if (lassummary.number_of_points_by_return[0]) fprintf(file_out, "WARNING: there %s %I64d point%s with return number 0\n", (lassummary.number_of_points_by_return[0] > 1 ? "are" : "is"), lassummary.number_of_points_by_return[0], (lassummary.number_of_points_by_return[0] > 1 ? "s" : ""));
        if (lasheader->version_minor < 4)
        {
          if (lassummary.number_of_points_by_return[6]) fprintf(file_out, "WARNING: there %s %I64d point%s with return number 6\n", (lassummary.number_of_points_by_return[6] > 1 ? "are" : "is"), lassummary.number_of_points_by_return[6], (lassummary.number_of_points_by_return[6] > 1 ? "s" : "")); 
          if (lassummary.number_of_points_by_return[7]) fprintf(file_out, "WARNING: there %s %I64d point%s with return number 7\n", (lassummary.number_of_points_by_return[7] > 1 ? "are" : "is"), lassummary.number_of_points_by_return[7], (lassummary.number_of_points_by_return[7] > 1 ? "s" : "")); 
        }
#else
        if (lassummary.number_of_points_by_return[0]) fprintf(file_out, "WARNING: there %s %lld point%s with return number 0\n", (lassummary.number_of_points_by_return[0] > 1 ? "are" : "is"), lassummary.number_of_points_by_return[0], (lassummary.number_of_points_by_return[0] > 1 ? "s" : "")); 
        if (lasheader->version_minor < 4)
        {
          if (lassummary.number_of_points_by_return[6]) fprintf(file_out, "WARNING: there %s %lld point%s with return number 6\n", (lassummary.number_of_points_by_return[6] > 1 ? "are" : "is"), lassummary.number_of_points_by_return[6], (lassummary.number_of_points_by_return[6] > 1 ? "s" : ""));
          if (lassummary.number_of_points_by_return[7]) fprintf(file_out, "WARNING: there %s %lld point%s with return number 7\n", (lassummary.number_of_points_by_return[7] > 1 ? "are" : "is"), lassummary.number_of_points_by_return[7], (lassummary.number_of_points_by_return[7] > 1 ? "s" : ""));
        }
#endif

        wrong_entry = false;

        if (lasheader->version_minor > 3)
        {
          for (i = 1; i < 16; i++) if (lassummary.number_of_returns[i]) wrong_entry = true;
          if (wrong_entry)
          {
           fprintf(file_out, "overview over extended number of returns of given pulse:"); 
#ifdef _WIN32
            for (i = 1; i < 16; i++) fprintf(file_out, " %I64d", lassummary.number_of_returns[i]);
#else
            for (i = 1; i < 16; i++) fprintf(file_out, " %lld", lassummary.number_of_returns[i]);
#endif
            fprintf(file_out, "\n"); 
          }
        }
        else
        {
          for (i = 1; i < 8; i++) if (lassummary.number_of_returns[i]) wrong_entry = true;
          if (wrong_entry)
          {
           fprintf(file_out, "overview over number of returns of given pulse:"); 
#ifdef _WIN32
            for (i = 1; i < 8; i++) fprintf(file_out, " %I64d", lassummary.number_of_returns[i]);
#else
            for (i = 1; i < 8; i++) fprintf(file_out, " %lld", lassummary.number_of_returns[i]);
#endif
            fprintf(file_out, "\n"); 
          }
        }

#ifdef _WIN32
        if (lassummary.number_of_returns[0]) fprintf(file_out, "WARNING: there are %I64d points with a number of returns of given pulse of 0\n", lassummary.number_of_returns[0]); 
#else
        if (lassummary.number_of_returns[0]) fprintf(file_out, "WARNING: there are %lld points with a number of returns of given pulse of 0\n", lassummary.number_of_returns[0]); 
#endif
      }

      if (file_out && !no_min_max)
      {
        wrong_entry = false;
        for (i = 0; i < 32; i++) if (lassummary.classification[i]) wrong_entry = true;
        if (lassummary.classification_synthetic || lassummary.classification_keypoint ||  lassummary.classification_withheld) wrong_entry = true;

        if (wrong_entry)
        {
          fprintf(file_out, "histogram of classification of points:\n"); 
#ifdef _WIN32
          for (i = 0; i < 32; i++) if (lassummary.classification[i]) fprintf(file_out, " %15I64d  %s (%u)\n", lassummary.classification[i], LASpointClassification[i], i);
          if (lassummary.classification_synthetic) fprintf(file_out, " +-> flagged as synthetic: %I64d\n", lassummary.classification_synthetic);
          if (lassummary.classification_keypoint) fprintf(file_out,  " +-> flagged as keypoints: %I64d\n", lassummary.classification_keypoint);
          if (lassummary.classification_withheld) fprintf(file_out,  " +-> flagged as withheld:  %I64d\n", lassummary.classification_withheld);
#else
          for (i = 0; i < 32; i++) if (lassummary.classification[i]) fprintf(file_out, " %15lld  %s (%u)\n", lassummary.classification[i], LASpointClassification[i], i);
          if (lassummary.classification_synthetic) fprintf(file_out, " +-> flagged as synthetic: %lld\n", lassummary.classification_synthetic);
          if (lassummary.classification_keypoint) fprintf(file_out,  " +-> flagged as keypoints: %lld\n", lassummary.classification_keypoint);
          if (lassummary.classification_withheld) fprintf(file_out,  " +-> flagged as withheld:  %lld\n", lassummary.classification_withheld);
#endif
        }

        if (lasreader->point.extended_point_type)
        {
#ifdef _WIN32
          if (lassummary.classification_extended_overlap) fprintf(file_out, " +-> flagged as extended overlap: %I64d\n", lassummary.classification_extended_overlap);
#else
          if (lassummary.classification_extended_overlap) fprintf(file_out, " +-> flagged as extended overlap: %lld\n", lassummary.classification_extended_overlap);
#endif

          wrong_entry = false;
          for (i = 32; i < 256; i++) if (lassummary.extended_classification[i]) wrong_entry = true;

          if (wrong_entry)
          {
            fprintf(file_out, "histogram of extended classification of points:\n"); 
  #ifdef _WIN32
            for (i = 32; i < 256; i++) if (lassummary.extended_classification[i]) fprintf(file_out, " %15I64d  extended classification (%u)\n", lassummary.extended_classification[i], i);
  #else
            for (i = 32; i < 256; i++) if (lassummary.extended_classification[i]) fprintf(file_out, " %15lld  extended classification (%u)\n", lassummary.extended_classification[i], i);
  #endif
          }
        }
      }

      if (lashistogram.active())
      {
        lashistogram.report(file_out);
        lashistogram.reset();
      }

      double value;
      if (repair_bb)
      {
        wrong_entry = false;
        if (lasheader->get_x(lassummary.max.get_X()) != lasheader->max_x) wrong_entry = true;
        if (lasheader->get_x(lassummary.min.get_X()) != lasheader->min_x) wrong_entry = true;
        if (lasheader->get_y(lassummary.max.get_Y()) != lasheader->max_y) wrong_entry = true;
        if (lasheader->get_y(lassummary.min.get_Y()) != lasheader->min_y) wrong_entry = true;
        if (lasheader->get_z(lassummary.max.get_Z()) != lasheader->max_z) wrong_entry = true;
        if (lasheader->get_z(lassummary.min.get_Z()) != lasheader->min_z) wrong_entry = true;
        if (wrong_entry)
        {
          fseek(file, 179, SEEK_SET);
          value = lasheader->get_x(lassummary.max.get_X()); fwrite(&value, sizeof(double), 1, file);
          value = lasheader->get_x(lassummary.min.get_X()); fwrite(&value, sizeof(double), 1, file);
          value = lasheader->get_y(lassummary.max.get_Y()); fwrite(&value, sizeof(double), 1, file);
          value = lasheader->get_y(lassummary.min.get_Y()); fwrite(&value, sizeof(double), 1, file);
          value = lasheader->get_z(lassummary.max.get_Z()); fwrite(&value, sizeof(double), 1, file);
          value = lasheader->get_z(lassummary.min.get_Z()); fwrite(&value, sizeof(double), 1, file);
          if (file_out) fprintf(file_out, "bounding box was repaired.\n");
        }
        else
        {
          if (file_out) fprintf(file_out, "bounding box is correct.\n");
        }
      }
      else
      {
        value = lasheader->get_x(lassummary.max.get_X());
        if (value > enlarged_max_x)
        {
          if (!no_warnings && file_out) fprintf(file_out, "WARNING: real max x larger than header max x by %lf\n", value - lasheader->max_x);
        }
        value = lasheader->get_x(lassummary.min.get_X());
        if (value < enlarged_min_x)
        {
          if (!no_warnings && file_out) fprintf(file_out, "WARNING: real min x smaller than header min x by %lf\n", lasheader->min_x - value);
        }
        value = lasheader->get_y(lassummary.max.get_Y());
        if (value > enlarged_max_y)
        {
          if (!no_warnings && file_out) fprintf(file_out, "WARNING: real max y larger than header max y by %lf\n", value - lasheader->max_y);
        }
        value = lasheader->get_y(lassummary.min.get_Y());
        if (value < enlarged_min_y)
        {
          if (!no_warnings && file_out) fprintf(file_out, "WARNING: real min y smaller than header min y by %lf\n", lasheader->min_y - value);
        }
        value = lasheader->get_z(lassummary.max.get_Z());
        if (value > enlarged_max_z)
        {
          if (!no_warnings && file_out) fprintf(file_out, "WARNING: real max z larger than header max z by %lf\n", value - lasheader->max_z);
        }
        value = lasheader->get_z(lassummary.min.get_Z());
        if (value < enlarged_min_z)
        {
          if (!no_warnings && file_out) fprintf(file_out, "WARNING: real min z smaller than header min z by %lf\n", lasheader->min_z - value);
        }
      }
    }

    if (file_out && (file_out != stdout) && (file_out != stderr)) fclose(file_out);
    laswriteopener.set_file_name(0);

    delete lasreader;
    if (file) fclose(file);
  }

  if (set_system_identifier) delete [] set_system_identifier;
  if (set_generating_software) delete [] set_generating_software;
  if (set_bounding_box) delete [] set_bounding_box;
  if (set_offset) delete [] set_offset;
  if (set_scale) delete [] set_scale;

  byebye(false, wait || (argc==1));

  return 0;
}
