--- /dev/null
+#include "libhpcs.h"
+#include "libhpcs_p.h"
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+char* hpcs_error_to_string(const enum HPCS_RetCode err)
+{
+ char* msg;
+
+ switch (err) {
+ case HPCS_OK:
+ msg = malloc(strlen(HPCS_OK_STR) + 1);
+ strcpy(msg, HPCS_OK_STR);
+ return msg;
+ case HPCS_E_NULLPTR:
+ msg = malloc(strlen(HPCS_E_NULLPTR_STR) + 1);
+ strcpy(msg, HPCS_E_NULLPTR_STR);
+ return msg;
+ case HPCS_E_CANT_OPEN:
+ msg = malloc(strlen(HPCS_E_CANT_OPEN_STR) + 1);
+ strcpy(msg, HPCS_E_CANT_OPEN_STR);
+ return msg;
+ case HPCS_E_PARSE_ERROR:
+ msg = malloc(strlen(HPCS_E_PARSE_ERROR_STR) + 1);
+ strcpy(msg, HPCS_E_PARSE_ERROR_STR);
+ return msg;
+ case HPCS_E_UNKNOWN_TYPE:
+ msg = malloc(strlen(HPCS_E_UNKNOWN_TYPE_STR) + 1);
+ strcpy(msg, HPCS_E_UNKNOWN_TYPE_STR);
+ return msg;
+ default:
+ msg = malloc(strlen(HPCS_E__UNKNOWN_EC_STR) + 1);
+ strcpy(msg, HPCS_E__UNKNOWN_EC_STR);
+ return msg;
+ }
+}
+
+enum HPCS_RetCode hpcs_read_file(const char* filename, struct HPCS_MeasuredData* mdata)
+{
+ FILE* datafile;
+ enum HPCS_ParseCode pret;
+ enum HPCS_RetCode ret;
+
+ if (mdata == NULL)
+ return HPCS_E_NULLPTR;
+
+ datafile = fopen(filename, "rb");
+ if (datafile == NULL)
+ return HPCS_E_CANT_OPEN;
+
+ pret = read_string_at_offset(datafile, DATA_OFFSET_FILE_DESC, &mdata->file_description);
+ if (pret != PARSE_OK) {
+ ret = HPCS_E_PARSE_ERROR;
+ goto out;
+ }
+ pret = read_string_at_offset(datafile, DATA_OFFSET_SAMPLE_INFO, &mdata->sample_info);
+ if (pret != PARSE_OK) {
+ ret = HPCS_E_PARSE_ERROR;
+ goto out;
+ }
+ pret = read_string_at_offset(datafile, DATA_OFFSET_OPERATOR_NAME, &mdata->operator_name);
+ if (pret != PARSE_OK) {
+ ret = HPCS_E_PARSE_ERROR;
+ goto out;
+ }
+ pret = read_date(datafile, &mdata->date);
+ if (pret != PARSE_OK) {
+ ret = HPCS_E_PARSE_ERROR;
+ goto out;
+ }
+ pret = read_string_at_offset(datafile, DATA_OFFSET_CS_VER, &mdata->cs_ver);
+ if (pret != PARSE_OK) {
+ ret = HPCS_E_PARSE_ERROR;
+ goto out;
+ }
+ pret = read_string_at_offset(datafile, DATA_OFFSET_Y_UNITS, &mdata->y_units);
+ if (pret != PARSE_OK) {
+ ret = HPCS_E_PARSE_ERROR;
+ goto out;
+ }
+ pret = read_string_at_offset(datafile, DATA_OFFSET_CS_REV, &mdata->cs_rev);
+ if (pret != PARSE_OK) {
+ ret = HPCS_E_PARSE_ERROR;
+ goto out;
+ }
+ pret = read_sampling_rate(datafile, &mdata->sampling_rate);
+ if (pret != PARSE_OK) {
+ ret = HPCS_E_PARSE_ERROR;
+ goto out;
+ }
+ pret = autodetect_file_type(datafile, &mdata->file_type);
+ if (pret != PARSE_OK) {
+ ret = HPCS_E_PARSE_ERROR;
+ goto out;
+ }
+
+ if (mdata->file_type == TYPE_CE_DAD) {
+ pret = read_dad_wavelength(datafile, WAVELENGTH_MEASURED, &mdata->dad_wavelength_msr);
+ if (pret != PARSE_OK && pret != PARSE_W_NO_DATA) {
+ ret = HPCS_E_PARSE_ERROR;
+ goto out;
+ }
+ pret = read_dad_wavelength(datafile, WAVELENGTH_REFERENCE, &mdata->dad_wavelength_ref);
+ if (pret != PARSE_OK && pret != PARSE_W_NO_DATA) {
+ ret = HPCS_E_PARSE_ERROR;
+ goto out;
+ }
+ }
+
+ switch (mdata->file_type) {
+ case TYPE_CE_CURRENT:
+ pret = read_fixed_signal(datafile, &mdata->data, &mdata->data_count, CE_CURRENT_STEP, mdata->sampling_rate);
+ break;
+ case TYPE_CE_CCD:
+ pret = read_floating_signal(datafile, &mdata->data, &mdata->data_count, CE_CCD_STEP, mdata->sampling_rate);
+ break;
+ case TYPE_CE_DAD:
+ pret = read_fixed_signal(datafile, &mdata->data, &mdata->data_count, CE_DAD_STEP, mdata->sampling_rate);
+ break;
+ case TYPE_CE_POWER:
+ case TYPE_CE_VOLTAGE:
+ pret = read_fixed_signal(datafile, &mdata->data, &mdata->data_count, CE_PWR_VOLT_STEP, mdata->sampling_rate);
+ break;
+ case TYPE_UNKNOWN:
+ ret = HPCS_E_UNKNOWN_TYPE;
+ goto out;
+ }
+
+ if (pret != PARSE_OK) {
+ ret = HPCS_E_PARSE_ERROR;
+ }
+ else
+ ret = HPCS_OK;
+out:
+ fclose(datafile);
+ return ret;
+}
+
+static enum HPCS_ParseCode autodetect_file_type(FILE* datafile, enum HPCS_File_Type* file_type)
+{
+ char* type_str;
+ char* type_id;
+ char* delim;
+ size_t len;
+ enum HPCS_ParseCode pret;
+
+ pret = read_string_at_offset(datafile, DATA_OFFSET_DEVSIG_INFO, &type_str);
+ if (pret != PARSE_OK)
+ return pret;
+
+ delim = strchr(type_str, DATA_FILE_COMMA);
+ if (delim == NULL) {
+ free(type_str);
+ return PARSE_E_NOT_FOUND;
+ }
+
+ len = delim - type_str;
+ type_id = malloc(len + 1);
+ memcpy(type_id, type_str, len);
+ type_id[len] = 0;
+
+ if (strcmp(FILE_TYPE_CE_CCD, type_id) == 0)
+ *file_type = TYPE_CE_CCD;
+ else if (strcmp(FILE_TYPE_CE_CURRENT, type_id) == 0)
+ *file_type = TYPE_CE_CURRENT;
+ else if (strstr(type_id, FILE_TYPE_CE_DAD) != NULL)
+ *file_type = TYPE_CE_DAD;
+ else if (strcmp(FILE_TYPE_CE_POWER, type_id) == 0)
+ *file_type = TYPE_CE_POWER;
+ else if (strcmp(FILE_TYPE_CE_VOLTAGE, type_id) == 0)
+ *file_type = TYPE_CE_VOLTAGE;
+ else
+ *file_type = TYPE_UNKNOWN;
+
+ return PARSE_OK;
+}
+
+static enum HPCS_DataCheckCode check_for_marker(const char* const segment, size_t* const next_marker_idx)
+{
+ if (segment[0] == BIN_MARKER_END && segment[1] == BIN_MARKER_END)
+ return DCHECK_EOF;
+ else if (segment[0] == BIN_MARKER_A && segment[1] != BIN_MARKER_END) {
+ *next_marker_idx += (uint8_t)segment[1] + 1;
+ return DCHECK_GOT_MARKER;
+ } else
+ return DCHECK_E_NO_MARKER;
+}
+
+static enum HPCS_ParseCode read_dad_wavelength(FILE* datafile, const enum HPCS_Wavelength_Type wl_type, uint16_t* const wavelength)
+{
+ char* start_idx, *end_idx, *temp, *type_str;
+ size_t len;
+ enum HPCS_ParseCode pret;
+
+ *wavelength = 0;
+ pret = read_string_at_offset(datafile, DATA_OFFSET_DEVSIG_INFO, &type_str);
+ if (pret != PARSE_OK)
+ return pret;
+
+ switch (wl_type) {
+ case WAVELENGTH_MEASURED:
+ start_idx = strstr(type_str, WAVELENGTH_MEASURED_TEXT);
+ break;
+ case WAVELENGTH_REFERENCE:
+ start_idx = strstr(type_str, WAVELENGTH_REFERENCE_TEXT);
+ break;
+ default:
+ return PARSE_E_INV_PARAM;
+ }
+
+ if (start_idx == NULL)
+ return PARSE_W_NO_DATA;
+
+ end_idx = strchr(start_idx, WAVELENGTH_DELIMITER_TEXT);
+ if (end_idx == NULL)
+ return PARSE_E_NOT_FOUND;
+
+ len = end_idx - (start_idx + 4);
+ temp = malloc(len + 1);
+ if (temp == NULL)
+ return PARSE_E_NO_MEM;
+ memcpy(temp, start_idx + 4, len);
+ temp[len] = 0;
+
+ *wavelength = strtoul(temp, NULL, 10);
+ free(temp);
+ return PARSE_OK;
+}
+
+static enum HPCS_ParseCode read_date(FILE* datafile, struct HPCS_Date* date)
+{
+ char* date_str;
+ char* date_time_delim;
+ char* dm_delim, *my_delim;
+ char* hm_delim, *ms_delim;
+ char temp[32];
+ size_t len;
+ enum HPCS_ParseCode pret;
+
+ pret = read_string_at_offset(datafile, DATA_OFFSET_DATE, &date_str);
+ if (pret != PARSE_OK)
+ return pret;
+
+ /* Find date / time delimiter */
+ date_time_delim = strchr(date_str, DATA_FILE_COMMA);
+ if (date_time_delim == NULL) {
+ free(date_str);
+ return PARSE_E_NOT_FOUND;
+ }
+
+ /* Get day */
+ dm_delim = strchr(date_str, DATA_FILE_DASH);
+ if (dm_delim == NULL) {
+ free(date_str);
+ return PARSE_E_NOT_FOUND;
+ }
+ len = dm_delim - date_str;
+ memcpy(temp, date_str, len);
+ temp[len] = 0;
+ date->day = strtoul(temp, NULL, 10);
+
+ /* Get month */
+ my_delim = strchr(dm_delim + 1, DATA_FILE_DASH);
+ if (dm_delim == NULL) {
+ free(date_str);
+ return PARSE_E_NOT_FOUND;
+ }
+ len = my_delim - (dm_delim + 1);
+ memcpy(temp, dm_delim + 1, len);
+ temp[len] = 0;
+ date->month = month_to_number(temp);
+
+ /* Get year */
+ len = date_time_delim - (my_delim + 1);
+ memcpy(temp, my_delim + 1, len);
+ temp[len] = 0;
+ date->year = strtoul(temp, NULL, 10);
+ if (date->year < 90) /* Y2K workaround */
+ date->year += 2000;
+
+ /* Get hour */
+ hm_delim = strchr(date_time_delim + 1, DATA_FILE_COLON);
+ if (hm_delim == NULL) {
+ free(date_str);
+ return PARSE_E_NOT_FOUND;
+ }
+ len = hm_delim - (date_time_delim + 1);
+ memcpy(temp, date_time_delim + 1, len);
+ temp[len] = 0;
+ date->hour = strtoul(temp, NULL, 10);
+
+ /* Get minute */
+ ms_delim = strchr(hm_delim + 1, DATA_FILE_COLON);
+ if (ms_delim == NULL) {
+ free(date_str);
+ return PARSE_E_NOT_FOUND;
+ }
+ len = ms_delim - (hm_delim + 1);
+ memcpy(temp, hm_delim + 1, len);
+ temp[len] = 0;
+ date->minute = strtoul(temp, NULL, 10);
+
+ /* Get second */
+ date->second = strtoul(ms_delim + 1, NULL, 10);
+
+ return PARSE_OK;
+}
+
+static uint8_t month_to_number(const char* const month)
+{
+ if (strcmp(MON_JAN_STR, month) == 0)
+ return 1;
+ else if (strcmp(MON_FEB_STR, month) == 0)
+ return 2;
+ else if (strcmp(MON_MAR_STR, month) == 0)
+ return 3;
+ else if (strcmp(MON_APR_STR, month) == 0)
+ return 4;
+ else if (strcmp(MON_MAY_STR, month) == 0)
+ return 5;
+ else if (strcmp(MON_JUN_STR, month) == 0)
+ return 6;
+ else if (strcmp(MON_JUL_STR, month) == 0)
+ return 7;
+ else if (strcmp(MON_AUG_STR, month) == 0)
+ return 8;
+ else if (strcmp(MON_SEP_STR, month) == 0)
+ return 9;
+ else if (strcmp(MON_OCT_STR, month) == 0)
+ return 10;
+ else if (strcmp(MON_NOV_STR, month) == 0)
+ return 11;
+ else if (strcmp(MON_DEC_STR, month) == 0)
+ return 12;
+ else
+ return 0;
+}
+
+static enum HPCS_ParseCode read_fixed_signal(FILE* datafile, struct HPCS_TVPair** pairs, size_t* pairs_count,
+ const HPCS_step step, const double sampling_rate)
+{
+ const double time_step = 1 / (60 * sampling_rate);
+ size_t alloc_size = 60 * sampling_rate;
+ bool read_file = true;
+ double value = 0;
+ double time = 0;
+ size_t segments_read = 0;
+ size_t data_segments_read = 0;
+ size_t next_marker_idx = 0;
+ char raw[2];
+ size_t r;
+ enum HPCS_DataCheckCode dret;
+
+ fseek(datafile, DATA_OFFSET_DATA_START, SEEK_SET);
+ if (feof(datafile))
+ return PARSE_E_OUT_OF_RANGE;
+
+ /* Data block must begin with a marker, read it */
+ r = fread(raw, SEGMENT_SIZE, 1, datafile);
+ if (r != 1)
+ return PARSE_E_CANT_READ;
+ segments_read++;
+
+ dret = check_for_marker(raw, &next_marker_idx);
+ switch (dret) {
+ case DCHECK_EOF:
+ case DCHECK_E_NO_MARKER:
+ return PARSE_E_NOT_FOUND; /* First segment is not a marker */
+ default:
+ break;
+ }
+
+ *pairs = malloc(sizeof(struct HPCS_TVPair) * alloc_size);
+ if (pairs == NULL)
+ return PARSE_E_NO_MEM;
+
+ while (read_file) {
+ if (ferror(datafile)) {
+ free(*pairs);
+ *pairs = NULL;
+ return PARSE_E_CANT_READ;
+ }
+ if (feof(datafile))
+ break;
+
+ r = fread(raw, SEGMENT_SIZE, 1, datafile);
+ if (r != 1) {
+ free(*pairs);
+ *pairs = NULL;
+ return PARSE_E_CANT_READ;
+ }
+ segments_read++;
+
+ if (alloc_size == data_segments_read) {
+ struct HPCS_TVPair* nptr;
+ alloc_size += 60 * sampling_rate;
+ nptr = realloc(*pairs, sizeof(struct HPCS_TVPair) * alloc_size);
+
+ if (nptr == NULL) {
+ free(*pairs);
+ *pairs = NULL;
+ return PARSE_E_NO_MEM;
+ }
+
+ *pairs = nptr;
+ }
+
+ if (segments_read - 1 == next_marker_idx) {
+ dret = check_for_marker(raw, &next_marker_idx);
+ switch (dret) {
+ case DCHECK_GOT_MARKER:
+ break;
+ case DCHECK_EOF:
+ read_file = false;
+ break;
+ default:
+ free(*pairs);
+ *pairs = NULL;
+ return PARSE_E_NOT_FOUND;
+ }
+ } else {
+ be_to_cpu(raw);
+ value += (*(int16_t*)(raw)) * step;
+
+ (*pairs)[data_segments_read].time = time;
+ (*pairs)[data_segments_read].value = value;
+ data_segments_read++;
+ time += time_step;
+ }
+ }
+
+ *pairs_count = data_segments_read;
+ return PARSE_OK;
+}
+
+static enum HPCS_ParseCode read_floating_signal(FILE* datafile, struct HPCS_TVPair** pairs, size_t* pairs_count,
+ const HPCS_step step, const double sampling_rate)
+{
+ const double time_step = 1 / (60 * sampling_rate);
+ size_t alloc_size = 60 * sampling_rate;
+ bool read_file = true;
+ double value = 0;
+ double time = 0;
+ size_t segments_read = 0;
+ size_t data_segments_read = 0;
+ size_t next_marker_idx = 0;
+ char raw[2];
+ size_t r;
+ enum HPCS_DataCheckCode dret;
+
+ fseek(datafile, DATA_OFFSET_DATA_START, SEEK_SET);
+ if (feof(datafile))
+ return PARSE_E_OUT_OF_RANGE;
+
+ r = fread(raw, SEGMENT_SIZE, 1, datafile);
+ if (r != 1)
+ return PARSE_E_CANT_READ;
+ segments_read++;
+
+ dret = check_for_marker(raw, &next_marker_idx);
+ switch (dret) {
+ case DCHECK_EOF:
+ case DCHECK_E_NO_MARKER:
+ return PARSE_E_NOT_FOUND;
+ default:
+ break;
+ }
+
+ *pairs = malloc(sizeof(struct HPCS_TVPair) * alloc_size);
+ if (*pairs == NULL)
+ return PARSE_E_NO_MEM;
+
+ while (read_file) {
+ if (ferror(datafile)) {
+ free(*pairs);
+ *pairs = NULL;
+ return PARSE_E_CANT_READ;
+ }
+ if (feof(datafile))
+ break;
+
+ r = fread(raw, SEGMENT_SIZE, 1, datafile);
+ if (r != 1) {
+ free(*pairs);
+ *pairs = NULL;
+ return PARSE_E_CANT_READ;
+ }
+ segments_read++;
+
+ /* Expand storage if there is more data than we can store */
+ if (alloc_size == data_segments_read) {
+ struct HPCS_TVPair* nptr;
+ alloc_size += 60 * sampling_rate;
+ nptr = realloc(*pairs, sizeof(struct HPCS_TVPair) * alloc_size);
+
+ if (nptr == NULL) {
+ free(*pairs);
+ *pairs = NULL;
+ return PARSE_E_NO_MEM;
+ }
+
+ *pairs = nptr;
+ }
+
+ /* Check for markers */
+ if (segments_read - 1 == next_marker_idx) {
+ dret = check_for_marker(raw, &next_marker_idx);
+ switch (dret) {
+ case DCHECK_GOT_MARKER:
+ break;
+ case DCHECK_EOF:
+ read_file = false;
+ break;
+ default:
+ free(*pairs);
+ *pairs = NULL;
+ return PARSE_E_NOT_FOUND;
+ }
+ } else {
+ /* Check for a sudden jump of value */
+ if (raw[0] == BIN_MARKER_JUMP && raw[1] == BIN_MARKER_END) {
+ char lraw[4];
+ int32_t _v;
+
+ fread(lraw, LARGE_SEGMENT_SIZE, 1, datafile);
+ if (feof(datafile) || ferror(datafile)) {
+ free(*pairs);
+ *pairs = NULL;
+ return PARSE_E_CANT_READ;
+ }
+
+ be_to_cpu(lraw);
+ _v = *(int32_t*)lraw;
+ value = _v * step;
+ } else {
+ int16_t _v;
+
+ be_to_cpu(raw);
+ _v = *(int16_t*)raw;
+ value += _v * step;
+ }
+
+ (*pairs)[data_segments_read].time = time;
+ (*pairs)[data_segments_read].value = value;
+ data_segments_read++;
+ time += time_step;
+ }
+ }
+
+ *pairs_count = data_segments_read;
+ return PARSE_OK;
+}
+
+static enum HPCS_ParseCode read_sampling_rate(FILE* datafile, double* sampling_rate)
+{
+ char raw[2];
+ uint16_t number;
+ size_t r;
+
+ fseek(datafile, DATA_OFFSET_SAMPLING_RATE, SEEK_SET);
+ if (feof(datafile))
+ return PARSE_E_OUT_OF_RANGE;
+
+ r = fread(raw, SEGMENT_SIZE, 1, datafile);
+ if (r != 1)
+ return PARSE_E_CANT_READ;
+
+ be_to_cpu(raw);
+ number = *(uint16_t*)(raw);
+ *sampling_rate = number / 10.0;
+
+ return PARSE_OK;
+}
+
+static enum HPCS_ParseCode read_string_at_offset(FILE* datafile, const HPCS_offset offset, char** const result)
+{
+ char* string;
+ uint8_t str_length, idx;
+ size_t r;
+
+ fseek(datafile, offset, SEEK_SET);
+ if (feof(datafile))
+ return PARSE_E_OUT_OF_RANGE;
+
+ r = fread(&str_length, SMALL_SEGMENT_SIZE, 1, datafile);
+ if (r != 1)
+ return PARSE_E_CANT_READ;
+
+ string = malloc(str_length + 1);
+ if (string == NULL)
+ return PARSE_E_NO_MEM;
+
+ for (idx = 0; idx < str_length; idx++) {
+ fread(string+idx, SMALL_SEGMENT_SIZE, 1, datafile);
+ fseek(datafile, SMALL_SEGMENT_SIZE, SEEK_CUR);
+ }
+ string[str_length] = 0;
+
+ *result = string;
+ return PARSE_OK;
+}
--- /dev/null
+#include <stdio.h>
+
+enum HPCS_DataCheckCode {
+ DCHECK_GOT_MARKER,
+ DCHECK_EOF,
+ DCHECK_E_NO_MARKER
+};
+
+enum HPCS_ParseCode {
+ PARSE_OK,
+ PARSE_E_OUT_OF_RANGE,
+ PARSE_E_NO_MEM,
+ PARSE_E_CANT_READ,
+ PARSE_E_NOT_FOUND,
+ PARSE_E_INV_PARAM,
+ PARSE_W_NO_DATA
+};
+
+enum HPCS_Wavelength_Type {
+ WAVELENGTH_MEASURED,
+ WAVELENGTH_REFERENCE
+};
+
+typedef size_t HPCS_offset;
+typedef double HPCS_step;
+typedef size_t HPCS_segsize;
+
+
+/* Identifiers of file types found at offset 0x1075 */
+const char* FILE_TYPE_CE_CCD = "HPCE1L";
+const char* FILE_TYPE_CE_CURRENT = "HPCE1C";
+const char* FILE_TYPE_CE_DAD = "DAD1";
+const char* FILE_TYPE_CE_VOLTAGE = "HPCE1V";
+const char* FILE_TYPE_CE_POWER = "HPCE1P";
+
+/* Char and text values */
+const char* WAVELENGTH_MEASURED_TEXT = "Sig=";
+const char* WAVELENGTH_REFERENCE_TEXT = "Ref=";
+const char WAVELENGTH_DELIMITER_TEXT = ',';
+const char DATA_FILE_COMMA = (const char)(0x2C);
+const char DATA_FILE_DASH = (const char)(0x2D);
+const char DATA_FILE_COLON = (const char)(0x3A);
+const char* MON_JAN_STR = "Jan";
+const char* MON_FEB_STR = "Feb";
+const char* MON_MAR_STR = "Mar";
+const char* MON_APR_STR = "Apr";
+const char* MON_MAY_STR = "May";
+const char* MON_JUN_STR = "Jun";
+const char* MON_JUL_STR = "Jul";
+const char* MON_AUG_STR = "Aug";
+const char* MON_SEP_STR = "Sep";
+const char* MON_OCT_STR = "Oct";
+const char* MON_NOV_STR = "Nov";
+const char* MON_DEC_STR = "Dec";
+
+/* Precision of measured values. */
+const HPCS_step CE_CURRENT_STEP = 0.01;
+const HPCS_step CE_CCD_STEP = 0.0000596046450027643;
+const HPCS_step CE_DAD_STEP = 0.000476837158203;
+const HPCS_step CE_PWR_VOLT_STEP = 0.001;
+
+/* Offsets containing data of interest in .ch files */
+const HPCS_offset DATA_OFFSET_FILE_DESC = 0x15B;
+const HPCS_offset DATA_OFFSET_SAMPLE_INFO = 0x35A;
+const HPCS_offset DATA_OFFSET_OPERATOR_NAME = 0x758;
+const HPCS_offset DATA_OFFSET_DATE = 0x957;
+const HPCS_offset DATA_OFFSET_METHOD_NAME = 0xA0E;
+const HPCS_offset DATA_OFFSET_CS_VER = 0xE11;
+const HPCS_offset DATA_OFFSET_CS_REV = 0xEDA;
+const HPCS_offset DATA_OFFSET_SAMPLING_RATE = 0x101C;
+const HPCS_offset DATA_OFFSET_Y_UNITS = 0x104C;
+const HPCS_offset DATA_OFFSET_DEVSIG_INFO = 0x1075;
+const HPCS_offset DATA_OFFSET_DATA_START = 0x1800;
+
+/* Values of markers found in .ch files */
+const char BIN_MARKER_A = 0x10;
+const char BIN_MARKER_END = 0x00;
+const char BIN_MARKER_JUMP = (const char)(0x80);
+
+const HPCS_segsize SMALL_SEGMENT_SIZE = 1;
+const HPCS_segsize SEGMENT_SIZE = 2;
+const HPCS_segsize LARGE_SEGMENT_SIZE = 4;
+
+const char* HPCS_OK_STR = "OK.";
+const char* HPCS_E_NULLPTR_STR = "Null pointer to measured data struct.";
+const char* HPCS_E_CANT_OPEN_STR = "Cannot open the specified file.";
+const char* HPCS_E_PARSE_ERROR_STR = "Cannot parse the specified file, it might be corrupted or of unknown type.";
+const char* HPCS_E_UNKNOWN_TYPE_STR = "The specified file contains an unknown type of measurement.";
+const char* HPCS_E__UNKNOWN_EC_STR = "Unknown error code.";
+
+static enum HPCS_ParseCode autodetect_file_type(FILE* datafile, enum HPCS_File_Type* file_type);
+static enum HPCS_DataCheckCode check_for_marker(const char* const segment, size_t* const next_marker_idx);
+static enum HPCS_ParseCode read_dad_wavelength(FILE* datafile, const enum HPCS_Wavelength_Type wl_type, uint16_t* const wavelength);
+static uint8_t month_to_number(const char* const month);
+static enum HPCS_ParseCode read_date(FILE* datafile, struct HPCS_Date* const date);
+static enum HPCS_ParseCode read_fixed_signal(FILE* datafile, struct HPCS_TVPair** pairs, size_t* pairs_count,
+ const HPCS_step step, const double sampling_rate);
+static enum HPCS_ParseCode read_floating_signal(FILE* datafile, struct HPCS_TVPair** pairs, size_t* pairs_count,
+ const HPCS_step step, const double sampling_rate);
+static enum HPCS_ParseCode read_sampling_rate(FILE* datafile, double* sampling_rate);
+static enum HPCS_ParseCode read_string_at_offset(FILE* datafile, const HPCS_offset, char** const result);
+
+
+#ifdef _HPCS_LITTLE_ENDIAN
+#define be_to_cpu(bytes) reverse_endianness((char*)bytes, sizeof(bytes));
+
+void reverse_endianness(char* bytes, size_t sz) {
+ size_t i;
+ for (i = 0; i < sz/2; i++) {
+ char t = bytes[i];
+ bytes[i] = bytes[sz - i - 1];
+ bytes[sz - i - 1] = t;
+ }
+
+}
+
+#elif defined _HPCS_BIG_ENDIAN
+#define be_to_cpu(bytes)
+#else
+#error "Endiannes has not been determined."
+#endif
+
+#ifdef NDEBUG
+void print_debug(const char* msg)
+{
+ fprintf(stderr, "%s\n"m msg);
+}
+#else
+void print_debug(const char* msg) { return; }
+#endif //NDEBUG
+