private static void read_color_images(KeyenceFile kfile, BinaryReader p)
        {
            KeyenceOffsetTable offtable = kfile.offset_table;

            kfile.color_peak = new KeyenceTrueColorImage();
            read_color_image(kfile, kfile.color_peak, offtable.color_peak, p);
            kfile.color_light = new KeyenceTrueColorImage();
            read_color_image(kfile, kfile.color_light, offtable.color_light, p);
        }
        private static void read_data_image(KeyenceFile kfile, KeyenceFalseColorImage image, uint offset, BinaryReader p)
        {
            uint size = (uint)p.BaseStream.Length;
            uint bps;

            if (offset == 0)
            {
                return;
            }

            if (size <= KEYENCE_FALSE_COLOR_IMAGE_MIN_SIZE || offset > size - KEYENCE_FALSE_COLOR_IMAGE_MIN_SIZE)
            {
                throw new Exception("Stream size not enouth to read");
            }

            p.BaseStream.Position = offset;

            image.width = p.ReadUInt32();
            if (err_DIMENSION(image.width))
            {
                throw new Exception("Dimension Error");
            }
            image.height = p.ReadUInt32();
            if (err_DIMENSION(image.height))
            {
                throw new Exception("Dimension Error");
            }

            image.bit_depth = p.ReadUInt32();
            if (image.bit_depth != 8 && image.bit_depth != 16 && image.bit_depth != 32)
            {
                throw new Exception("BPP Error");
            }

            bps = image.bit_depth / 8;

            image.compression = p.ReadUInt32();
            image.byte_size   = p.ReadUInt32();
            if (err_SIZE_MISMATCH(image.width * image.height * bps, image.byte_size, true))
            {
                throw new Exception("Size Mismatch Error");
            }

            image.palette_range_min = p.ReadUInt32();
            image.palette_range_max = p.ReadUInt32();

            p.BaseStream.Read(image.palette, 0, image.palette.Length);

            if (size - offset - KEYENCE_FALSE_COLOR_IMAGE_MIN_SIZE < image.byte_size)
            {
                throw new Exception("Stream size not enouth to read");
            }
            image.data = p.ReadBytes((int)image.byte_size);
            kfile.nimages++;
        }
        private static void read_data_images(KeyenceFile kfile, BinaryReader p)
        {
            KeyenceOffsetTable offtable = kfile.offset_table;
            uint i;

            for (i = 0; i < kfile.light.Length; i++)
            {
                kfile.light[i] = new KeyenceFalseColorImage();
                read_data_image(kfile, kfile.light[i], offtable.light[i], p);
            }
            for (i = 0; i < kfile.height.Length; i++)
            {
                kfile.height[i] = new KeyenceFalseColorImage();
                read_data_image(kfile, kfile.height[i], offtable.height[i], p);
            }
        }
        private static void read_line_meas(KeyenceFile kfile, BinaryReader p)
        {
            uint size = (uint)p.BaseStream.Length;
            uint off  = kfile.offset_table.line_measure;
            uint i;

            if (off == 0)
            {
                return;
            }

            if (size <= KEYENCE_LINE_MEASUREMENT_SIZE || off > size - KEYENCE_LINE_MEASUREMENT_SIZE)
            {
                throw new Exception("Stream size not enouth to read");
            }

            p.BaseStream.Position = off;

            kfile.line_measure = new KeyenceLineMeasurement();
            KeyenceLineMeasurement linemeas = kfile.line_measure;

            linemeas.size = p.ReadUInt32();
            if (size < KEYENCE_LINE_MEASUREMENT_SIZE)
            {
                throw new Exception("Stream size not enouth to read");
            }
            linemeas.line_width = p.ReadUInt32();

            /* XXX: We should use the real length even though the format description
             * seems to specify a fixed length.  Also note that only the first data
             * block is supposed to be used; the rest it reserved. */
            for (i = 0; i < linemeas.light.Length; i++)
            {
                linemeas.light[i] = p.ReadBytes(KEYENCE_LINE_MEASUREMENT_LEN * sizeof(UInt16));
            }
            for (i = 0; i < linemeas.height.Length; i++)
            {
                linemeas.height[i] = p.ReadBytes(KEYENCE_LINE_MEASUREMENT_LEN * sizeof(UInt32));
            }
        }
        private static void read_character_strs(KeyenceFile kfile, BinaryReader p)
        {
            KeyenceCharacterStrings charstrs;
            uint remsize = (uint)p.BaseStream.Length;
            uint off     = kfile.offset_table.string_data;

            if (off == 0)
            {
                return;
            }

            if (remsize < off)
            {
                throw new Exception("Stream size not enouth to read");
            }

            p.BaseStream.Position = off;
            remsize           -= off;
            charstrs           = kfile.char_strs = new KeyenceCharacterStrings();
            charstrs.title     = read_character_str(p, ref remsize);
            charstrs.lens_name = read_character_str(p, ref remsize);
        }
        public static KeyenceFile LoadVk4FromStream(Stream stream)
        {
            using (BinaryReader p = new BinaryReader(stream)) {
                KeyenceFile kfile = new KeyenceFile();

                kfile.header       = read_header(p);
                kfile.offset_table = read_offset_table(p);
                kfile.meas_conds   = read_meas_conds(p);
                read_assembly_info(kfile, p);
                read_data_images(kfile, p);
                read_color_images(kfile, p);
                read_line_meas(kfile, p);
                read_character_strs(kfile, p);

                if (kfile.nimages == 0)
                {
                    throw new Exception("ni image data");
                }

                return(kfile);
            }
        }
        private static void read_assembly_info(KeyenceFile kfile, BinaryReader p)
        {
            uint size = (uint)p.BaseStream.Length;
            uint off = kfile.offset_table.assemble;
            uint remsize, nfiles, i, j;

            if (off == 0)
            {
                return;
            }

            if (size <= KEYENCE_ASSEMBLY_HEADERS_SIZE || off > size - KEYENCE_ASSEMBLY_HEADERS_SIZE)
            {
                throw new Exception("Stream size not enouth to read");
            }

            p.BaseStream.Position = off;

            kfile.assembly_info            = new KeyenceAssemblyInformation();
            kfile.assembly_info.size       = p.ReadUInt32();
            kfile.assembly_info.file_type  = (KeyenceFileType)p.ReadUInt16();
            kfile.assembly_info.stage_type = p.ReadUInt16();
            kfile.assembly_info.x_position = p.ReadUInt32();
            kfile.assembly_info.y_position = p.ReadUInt32();

            kfile.assembly_conds = new KeyenceAssemblyConditions();
            kfile.assembly_conds.auto_adjustment = p.ReadByte();
            kfile.assembly_conds.source          = p.ReadByte();
            kfile.assembly_conds.thin_out        = p.ReadUInt16();
            kfile.assembly_conds.count_x         = p.ReadUInt16();
            kfile.assembly_conds.count_y         = p.ReadUInt16();

            nfiles = kfile.assembly_conds.count_x * kfile.assembly_conds.count_y;
            if (nfiles == 0)
            {
                return;
            }

            remsize = size - KEYENCE_ASSEMBLY_HEADERS_SIZE - off;

            if (remsize / nfiles < KEYENCE_ASSEMBLY_FILE_SIZE)
            {
                /* Apparently there can be large counts but no actual assembly data.
                 * I do not understand but we to not use the infomation for anything
                 * anyway. */
                kfile.assembly_conds.count_x = 0;
                kfile.assembly_conds.count_y = 0;
                kfile.assembly_nfiles        = 0;
                return;
            }

            kfile.assembly_nfiles = nfiles;
            kfile.assembly_files  = new KeyenceAssemblyFile[nfiles];
            for (i = 0; i < nfiles; i++)
            {
                kfile.assembly_files[i] = new KeyenceAssemblyFile();
                KeyenceAssemblyFile kafile = kfile.assembly_files[i];

                for (j = 0; j < kafile.source_file.Length; j++)
                {
                    kafile.source_file[j] = p.ReadUInt16();
                }
                kafile.pos_x        = p.ReadByte();
                kafile.pos_y        = p.ReadByte();
                kafile.datums_pos   = p.ReadByte();
                kafile.fix_distance = p.ReadByte();
                kafile.distance_x   = p.ReadUInt32();
                kafile.distance_y   = p.ReadUInt32();
            }
        }