DSRemote/edflib.c

6392 wiersze
133 KiB
C

/*
*****************************************************************************
*
* Copyright (c) 2009 - 2023 Teunis van Beelen
* All rights reserved.
*
* Email: teuniz@protonmail.com
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************
*/
/* compile with options "-D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE" */
#include "edflib.h"
#define EDFLIB_VERSION (123)
#define EDFLIB_MAXFILES (64)
#if defined(__APPLE__) || defined(__MACH__) || defined(__APPLE_CC__) || defined(__HAIKU__) || defined(__ANDROID__)
#define fopeno fopen
#else
#define fseeko fseeko64
#define ftello ftello64
#define fopeno fopen64
#endif
#ifdef _WIN32
#ifndef __MINGW32__
/* needed for visual c */
#undef fseeko
#define fseeko _fseeki64
#undef ftello
#define ftello _ftelli64
#undef fopeno
#define fopeno fopen
#endif
#endif
/* max size of annotationtext */
#define EDFLIB_WRITE_MAX_ANNOTATION_LEN (40)
/* bytes in datarecord for EDF annotations, must be an integer multiple of three and two */
#define EDFLIB_ANNOTATION_BYTES (114)
/* for writing only */
#define EDFLIB_MAX_ANNOTATION_CHANNELS (64)
#define EDFLIB_ANNOT_MEMBLOCKSZ (1000)
struct edfparamblock{
char label[17];
char transducer[81];
char physdimension[9];
double phys_min;
double phys_max;
int dig_min;
int dig_max;
char prefilter[81];
int smp_per_record;
char reserved[33];
double offset;
int buf_offset;
double bitvalue;
int annotation;
long long sample_pntr;
};
struct edfhdrblock{
FILE *file_hdl;
char path[1024];
int writemode;
char version[32];
char patient[81];
char recording[81];
char plus_patientcode[81];
char plus_gender[16];
char plus_birthdate[16];
int plus_birthdate_day;
int plus_birthdate_month;
int plus_birthdate_year;
char plus_patient_name[81];
char plus_patient_additional[81];
char plus_startdate[16];
char plus_admincode[81];
char plus_technician[81];
char plus_equipment[81];
char plus_recording_additional[81];
long long l_starttime;
int startdate_day;
int startdate_month;
int startdate_year;
int starttime_second;
int starttime_minute;
int starttime_hour;
char reserved[45];
int hdrsize;
int edfsignals;
long long datarecords;
int recordsize;
int annot_ch[EDFLIB_MAXSIGNALS];
int nr_annot_chns;
int mapped_signals[EDFLIB_MAXSIGNALS];
int edf;
int edfplus;
int bdf;
int bdfplus;
int discontinuous;
int signal_write_sequence_pos;
long long starttime_offset;
double data_record_duration;
long long long_data_record_duration;
int annots_in_file;
int annotlist_sz;
int total_annot_bytes;
int eq_sf;
char *wrbuf;
int wrbufsize;
struct edfparamblock *edfparam;
};
static struct edf_annotationblock{
long long onset;
long long duration_l;
char duration[16];
char annotation[EDFLIB_MAX_ANNOTATION_LEN + 1];
} *annotationslist[EDFLIB_MAXFILES];
static struct edf_write_annotationblock{
long long onset;
long long duration;
char annotation[EDFLIB_WRITE_MAX_ANNOTATION_LEN + 1];
} *write_annotationslist[EDFLIB_MAXFILES];
static int edf_files_open=0;
static struct edfhdrblock *hdrlist[EDFLIB_MAXFILES];
static struct edfhdrblock * edflib_check_edf_file(FILE *, int *);
static int edflib_is_integer_number(char *);
static int edflib_is_number(char *);
static long long edflib_get_long_duration(char *);
static int edflib_get_annotations(struct edfhdrblock *, int, int);
static int edflib_is_duration_number(char *);
static int edflib_is_onset_number(char *);
static long long edflib_get_long_time(char *);
static int edflib_write_edf_header(struct edfhdrblock *);
static void edflib_latin1_to_ascii(char *, int);
static void edflib_latin12utf8(char *, int);
static void edflib_remove_padding_trailing_spaces(char *);
static int edflib_atoi_nonlocalized(const char *);
static double edflib_atof_nonlocalized(const char *);
static int edflib_snprint_number_nonlocalized(char *, double, int);
/*
static int edflib_sprint_int_number_nonlocalized(char *, int, int, int);
*/
static int edflib_snprint_ll_number_nonlocalized(char *, long long, int, int, int);
static int edflib_fprint_int_number_nonlocalized(FILE *, int, int, int);
static int edflib_fprint_ll_number_nonlocalized(FILE *, long long, int, int);
static int edflib_write_tal(struct edfhdrblock *, FILE *);
static int edflib_strlcpy(char *, const char *, int);
static int edflib_strlcat(char *, const char *, int);
int edflib_is_file_used(const char *path)
{
int i;
for(i=0; i<EDFLIB_MAXFILES; i++)
{
if(hdrlist[i]!=NULL)
{
if(!(strcmp(path, hdrlist[i]->path))) return 1;
}
}
return 0;
}
int edflib_get_number_of_open_files()
{
return edf_files_open;
}
int edflib_get_handle(int file_number)
{
int i, file_count=0;
for(i=0; i<EDFLIB_MAXFILES; i++)
{
if(hdrlist[i]!=NULL)
{
if(file_count++ == file_number) return i;
}
}
return -1;
}
int edfopen_file_readonly(const char *path, struct edf_hdr_struct *edfhdr, int read_annotations_mode)
{
int i, j,
channel,
edf_error;
FILE *file;
struct edfhdrblock *hdr;
union
{
char four[4];
int one;
} byte_order_test_var;
memset(edfhdr, 0, sizeof(struct edf_hdr_struct));
/* avoid surprises! */
if((sizeof(char) != 1) ||
(sizeof(short) != 2) ||
(sizeof(int) != 4) ||
(sizeof(long long) != 8) ||
(sizeof(float) != 4) ||
(sizeof(double) != 8))
{
edfhdr->filetype = EDFLIB_ARCH_ERROR;
return -1;
}
/* check endianness! */
byte_order_test_var.one = 0x03020100;
if((byte_order_test_var.four[0] != 0) ||
(byte_order_test_var.four[1] != 1) ||
(byte_order_test_var.four[2] != 2) ||
(byte_order_test_var.four[3] != 3))
{
edfhdr->filetype = EDFLIB_ARCH_ERROR;
return -1;
}
if((read_annotations_mode<0)||(read_annotations_mode>2))
{
edfhdr->filetype = EDFLIB_INVALID_READ_ANNOTS_VALUE;
return -1;
}
if(edf_files_open>=EDFLIB_MAXFILES)
{
edfhdr->filetype = EDFLIB_MAXFILES_REACHED;
return -1;
}
for(i=0; i<EDFLIB_MAXFILES; i++)
{
if(hdrlist[i]!=NULL)
{
if(!(strcmp(path, hdrlist[i]->path)))
{
edfhdr->filetype = EDFLIB_FILE_ALREADY_OPENED;
return -1;
}
}
}
file = fopeno(path, "rb");
if(file==NULL)
{
edfhdr->filetype = EDFLIB_NO_SUCH_FILE_OR_DIRECTORY;
return -1;
}
hdr = edflib_check_edf_file(file, &edf_error);
if(hdr==NULL)
{
edfhdr->filetype = edf_error;
fclose(file);
return -1;
}
if(hdr->discontinuous)
{
edfhdr->filetype = EDFLIB_FILE_IS_DISCONTINUOUS;
free(hdr->edfparam);
free(hdr);
fclose(file);
return -1;
}
for(i=0; i<EDFLIB_MAXFILES; i++)
{
if(hdrlist[i]==NULL)
{
hdrlist[i] = hdr;
edfhdr->handle = i;
break;
}
}
if((hdr->edf)&&(!(hdr->edfplus)))
{
edfhdr->filetype = EDFLIB_FILETYPE_EDF;
}
if(hdr->edfplus)
{
edfhdr->filetype = EDFLIB_FILETYPE_EDFPLUS;
}
if((hdr->bdf)&&(!(hdr->bdfplus)))
{
edfhdr->filetype = EDFLIB_FILETYPE_BDF;
}
if(hdr->bdfplus)
{
edfhdr->filetype = EDFLIB_FILETYPE_BDFPLUS;
}
edfhdr->edfsignals = hdr->edfsignals - hdr->nr_annot_chns;
edfhdr->file_duration = hdr->long_data_record_duration * hdr->datarecords;
edfhdr->startdate_day = hdr->startdate_day;
edfhdr->startdate_month = hdr->startdate_month;
edfhdr->startdate_year = hdr->startdate_year;
edfhdr->starttime_hour = hdr->starttime_hour;
edfhdr->starttime_second = hdr->starttime_second;
edfhdr->starttime_minute = hdr->starttime_minute;
edfhdr->starttime_subsecond = hdr->starttime_offset;
edfhdr->datarecords_in_file = hdr->datarecords;
edfhdr->datarecord_duration = hdr->long_data_record_duration;
annotationslist[edfhdr->handle] = NULL;
hdr->annotlist_sz = 0;
hdr->annots_in_file = 0;
edfhdr->annotations_in_file = 0LL;
if((!(hdr->edfplus))&&(!(hdr->bdfplus)))
{
edflib_strlcpy(edfhdr->patient, hdr->patient, 81);
edflib_strlcpy(edfhdr->recording, hdr->recording, 81);
}
else
{
edflib_strlcpy(edfhdr->patientcode, hdr->plus_patientcode, 81);
edflib_strlcpy(edfhdr->gender, hdr->plus_gender, 16);
edflib_strlcpy(edfhdr->birthdate, hdr->plus_birthdate, 16);
edfhdr->birthdate_day = hdr->plus_birthdate_day;
edfhdr->birthdate_month = hdr->plus_birthdate_month;
edfhdr->birthdate_year = hdr->plus_birthdate_year;
edflib_strlcpy(edfhdr->patient_name, hdr->plus_patient_name, 81);
edflib_strlcpy(edfhdr->patient_additional, hdr->plus_patient_additional, 81);
edflib_strlcpy(edfhdr->admincode, hdr->plus_admincode, 81);
edflib_strlcpy(edfhdr->technician, hdr->plus_technician, 81);
edflib_strlcpy(edfhdr->equipment, hdr->plus_equipment, 81);
edflib_strlcpy(edfhdr->recording_additional, hdr->plus_recording_additional, 81);
if(edflib_get_annotations(hdr, edfhdr->handle, read_annotations_mode))
{
edfhdr->filetype = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
fclose(file);
free(hdr->edfparam);
hdr->edfparam = NULL;
free(hdr);
hdr = NULL;
hdrlist[edfhdr->handle] = NULL;
free(annotationslist[edfhdr->handle]);
annotationslist[edfhdr->handle] = NULL;
return -1;
}
edfhdr->starttime_subsecond = hdr->starttime_offset;
edfhdr->annotations_in_file = hdr->annots_in_file;
}
edflib_strlcpy(hdr->path, path, 1024);
edf_files_open++;
j = 0;
for(i=0; i<hdr->edfsignals; i++)
{
if(!(hdr->edfparam[i].annotation))
{
hdr->mapped_signals[j++] = i;
}
}
for(i=0; i<edfhdr->edfsignals; i++)
{
channel = hdr->mapped_signals[i];
edflib_strlcpy(edfhdr->signalparam[i].label, hdr->edfparam[channel].label, 17);
edflib_strlcpy(edfhdr->signalparam[i].transducer, hdr->edfparam[channel].transducer, 81);
edflib_strlcpy(edfhdr->signalparam[i].physdimension, hdr->edfparam[channel].physdimension, 9);
edflib_strlcpy(edfhdr->signalparam[i].prefilter, hdr->edfparam[channel].prefilter, 81);
edfhdr->signalparam[i].smp_in_file = hdr->edfparam[channel].smp_per_record * hdr->datarecords;
edfhdr->signalparam[i].phys_max = hdr->edfparam[channel].phys_max;
edfhdr->signalparam[i].phys_min = hdr->edfparam[channel].phys_min;
edfhdr->signalparam[i].dig_max = hdr->edfparam[channel].dig_max;
edfhdr->signalparam[i].dig_min = hdr->edfparam[channel].dig_min;
edfhdr->signalparam[i].smp_in_datarecord = hdr->edfparam[channel].smp_per_record;
}
return 0;
}
int edfclose_file(int handle)
{
struct edf_write_annotationblock *annot2;
int i, j, k, n, p, err,
datrecsize,
nmemb;
long long offset,
datarecords;
char str[EDFLIB_ANNOTATION_BYTES * 2];
struct edfhdrblock *hdr;
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
hdr = hdrlist[handle];
if(hdr->writemode)
{
if(hdr->datarecords == 0LL)
{
err = edflib_write_edf_header(hdr);
if(err)
{
fclose(hdr->file_hdl);
free(hdr->edfparam);
free(hdr->wrbuf);
free(hdr);
hdrlist[handle] = NULL;
free(write_annotationslist[handle]);
write_annotationslist[handle] = NULL;
edf_files_open--;
return err;
}
for(k=0; k<hdr->annots_in_file; k++)
{
annot2 = write_annotationslist[handle] + k;
p = edflib_fprint_ll_number_nonlocalized(hdr->file_hdl, (hdr->datarecords * hdr->long_data_record_duration + hdr->starttime_offset) / EDFLIB_TIME_DIMENSION, 0, 1);
if((hdr->long_data_record_duration % EDFLIB_TIME_DIMENSION) || (hdr->starttime_offset))
{
fputc('.', hdr->file_hdl);
p++;
p += edflib_fprint_ll_number_nonlocalized(hdr->file_hdl, (hdr->datarecords * hdr->long_data_record_duration + hdr->starttime_offset) % EDFLIB_TIME_DIMENSION, 7, 0);
}
fputc(20, hdr->file_hdl);
fputc(20, hdr->file_hdl);
p += 2;
for(; p<hdr->total_annot_bytes; p++)
{
fputc(0, hdr->file_hdl);
}
hdr->datarecords++;
}
}
if(hdr->datarecords<100000000LL)
{
fseeko(hdr->file_hdl, 236LL, SEEK_SET);
p = edflib_fprint_int_number_nonlocalized(hdr->file_hdl, (int)(hdr->datarecords), 0, 0);
if(p < 2)
{
fputc(' ', hdr->file_hdl);
}
}
datarecords = 0LL;
offset = (long long)((hdr->edfsignals + hdr->nr_annot_chns + 1) * 256);
datrecsize = hdr->total_annot_bytes;
for(i=0; i<hdr->edfsignals; i++)
{
if(hdr->edf)
{
offset += (long long)(hdr->edfparam[i].smp_per_record * 2);
datrecsize += (hdr->edfparam[i].smp_per_record * 2);
}
else
{
offset += (long long)(hdr->edfparam[i].smp_per_record * 3);
datrecsize += (hdr->edfparam[i].smp_per_record * 3);
}
}
j = 0;
for(k=0; k<hdr->annots_in_file; k++)
{
annot2 = write_annotationslist[handle] + k;
annot2->onset += hdr->starttime_offset / 1000LL;
p = 0;
if(j==0) // first annotation signal
{
if(fseeko(hdr->file_hdl, offset, SEEK_SET))
{
break;
}
p += edflib_snprint_ll_number_nonlocalized(str, (datarecords * hdr->long_data_record_duration + hdr->starttime_offset) / EDFLIB_TIME_DIMENSION, 0, 1, EDFLIB_ANNOTATION_BYTES * 2);
if((hdr->long_data_record_duration % EDFLIB_TIME_DIMENSION) || (hdr->starttime_offset))
{
str[p++] = '.';
n = edflib_snprint_ll_number_nonlocalized(str + p, (datarecords * hdr->long_data_record_duration + hdr->starttime_offset) % EDFLIB_TIME_DIMENSION, 7, 0, (EDFLIB_ANNOTATION_BYTES * 2) - p);
p += n;
}
str[p++] = 20;
str[p++] = 20;
str[p++] = 0;
}
n = edflib_snprint_ll_number_nonlocalized(str + p, annot2->onset / 10000LL, 0, 1, (EDFLIB_ANNOTATION_BYTES * 2) - p);
p += n;
if(annot2->onset % 10000LL)
{
str[p++] = '.';
n = edflib_snprint_ll_number_nonlocalized(str + p, annot2->onset % 10000LL, 4, 0, (EDFLIB_ANNOTATION_BYTES * 2) - p);
p += n;
}
if(annot2->duration>=0LL)
{
str[p++] = 21;
n = edflib_snprint_ll_number_nonlocalized(str + p, annot2->duration / 10000LL, 0, 0, (EDFLIB_ANNOTATION_BYTES * 2) - p);
p += n;
if(annot2->duration % 10000LL)
{
str[p++] = '.';
n = edflib_snprint_ll_number_nonlocalized(str + p, annot2->duration % 10000LL, 4, 0, (EDFLIB_ANNOTATION_BYTES * 2) - p);
p += n;
}
}
str[p++] = 20;
for(i=0; i<EDFLIB_WRITE_MAX_ANNOTATION_LEN; i++)
{
if(annot2->annotation[i]==0)
{
break;
}
str[p++] = annot2->annotation[i];
}
str[p++] = 20;
for(; p<EDFLIB_ANNOTATION_BYTES; p++)
{
str[p] = 0;
}
nmemb = fwrite(str, EDFLIB_ANNOTATION_BYTES, 1, hdr->file_hdl);
if(nmemb != 1)
{
break;
}
j++;
if(j >= hdr->nr_annot_chns)
{
j = 0;
offset += datrecsize;
datarecords++;
if(datarecords>=hdr->datarecords)
{
break;
}
}
}
free(write_annotationslist[handle]);
}
else
{
free(annotationslist[handle]);
}
fclose(hdr->file_hdl);
free(hdr->edfparam);
free(hdr->wrbuf);
free(hdr);
hdrlist[handle] = NULL;
edf_files_open--;
return 0;
}
long long edfseek(int handle, int edfsignal, long long offset, int whence)
{
long long smp_in_file;
int channel;
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(edfsignal<0) return -1;
if(hdrlist[handle]->writemode) return -1;
if(edfsignal>=(hdrlist[handle]->edfsignals - hdrlist[handle]->nr_annot_chns)) return -1;
channel = hdrlist[handle]->mapped_signals[edfsignal];
smp_in_file = hdrlist[handle]->edfparam[channel].smp_per_record * hdrlist[handle]->datarecords;
if(whence==EDFSEEK_SET)
{
hdrlist[handle]->edfparam[channel].sample_pntr = offset;
}
if(whence==EDFSEEK_CUR)
{
hdrlist[handle]->edfparam[channel].sample_pntr += offset;
}
if(whence==EDFSEEK_END)
{
hdrlist[handle]->edfparam[channel].sample_pntr =
(hdrlist[handle]->edfparam[channel].smp_per_record * hdrlist[handle]->datarecords) + offset;
}
if(hdrlist[handle]->edfparam[channel].sample_pntr > smp_in_file)
{
hdrlist[handle]->edfparam[channel].sample_pntr = smp_in_file;
}
if(hdrlist[handle]->edfparam[channel].sample_pntr < 0LL)
{
hdrlist[handle]->edfparam[channel].sample_pntr = 0LL;
}
return hdrlist[handle]->edfparam[channel].sample_pntr;
}
long long edftell(int handle, int edfsignal)
{
int channel;
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(edfsignal<0) return -1;
if(hdrlist[handle]->writemode) return -1;
if(edfsignal>=(hdrlist[handle]->edfsignals - hdrlist[handle]->nr_annot_chns)) return -1;
channel = hdrlist[handle]->mapped_signals[edfsignal];
return hdrlist[handle]->edfparam[channel].sample_pntr;
}
void edfrewind(int handle, int edfsignal)
{
int channel;
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return;
if(hdrlist[handle]==NULL) return;
if(edfsignal<0) return;
if(hdrlist[handle]->writemode) return;
if(edfsignal>=(hdrlist[handle]->edfsignals - hdrlist[handle]->nr_annot_chns)) return;
channel = hdrlist[handle]->mapped_signals[edfsignal];
hdrlist[handle]->edfparam[channel].sample_pntr = 0LL;
}
int edfread_physical_samples(int handle, int edfsignal, int n, double *buf)
{
int bytes_per_smpl=2,
tmp,
i,
channel;
double phys_bitvalue,
phys_offset;
long long smp_in_file,
offset,
sample_pntr,
smp_per_record,
jump;
struct edfhdrblock *hdr;
union {
unsigned int one;
signed int one_signed;
unsigned short two[2];
signed short two_signed[2];
unsigned char four[4];
} var;
FILE *file;
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(edfsignal<0) return -1;
if(hdrlist[handle]->writemode) return -1;
if(edfsignal>=(hdrlist[handle]->edfsignals - hdrlist[handle]->nr_annot_chns)) return -1;
channel = hdrlist[handle]->mapped_signals[edfsignal];
if(n<0LL) return -1;
if(n==0LL) return 0LL;
hdr = hdrlist[handle];
if(hdr->edf)
{
bytes_per_smpl = 2;
}
if(hdr->bdf)
{
bytes_per_smpl = 3;
}
smp_in_file = hdr->edfparam[channel].smp_per_record * hdr->datarecords;
if((hdr->edfparam[channel].sample_pntr + n) > smp_in_file)
{
n = smp_in_file - hdr->edfparam[channel].sample_pntr;
if(n==0) return 0LL;
if(n<0) return -1;
}
file = hdr->file_hdl;
offset = hdr->hdrsize;
offset += (hdr->edfparam[channel].sample_pntr / hdr->edfparam[channel].smp_per_record) * hdr->recordsize;
offset += hdr->edfparam[channel].buf_offset;
offset += ((hdr->edfparam[channel].sample_pntr % hdr->edfparam[channel].smp_per_record) * bytes_per_smpl);
fseeko(file, offset, SEEK_SET);
sample_pntr = hdr->edfparam[channel].sample_pntr;
smp_per_record = hdr->edfparam[channel].smp_per_record;
jump = hdr->recordsize - (smp_per_record * bytes_per_smpl);
phys_bitvalue = hdr->edfparam[channel].bitvalue;
phys_offset = hdr->edfparam[channel].offset;
if(hdr->edf)
{
for(i=0; i<n; i++)
{
if(!(sample_pntr%smp_per_record))
{
if(i)
{
fseeko(file, jump, SEEK_CUR);
}
}
var.four[0] = fgetc(file);
tmp = fgetc(file);
if(tmp==EOF)
{
return -1;
}
var.four[1] = tmp;
if(var.two_signed[0] > hdr->edfparam[channel].dig_max)
{
var.two_signed[0] = hdr->edfparam[channel].dig_max;
}
else if(var.two_signed[0] < hdr->edfparam[channel].dig_min)
{
var.two_signed[0] = hdr->edfparam[channel].dig_min;
}
buf[i] = phys_bitvalue * (phys_offset + (double)var.two_signed[0]);
sample_pntr++;
}
}
if(hdr->bdf)
{
for(i=0; i<n; i++)
{
if(!(sample_pntr%smp_per_record))
{
if(i)
{
fseeko(file, jump, SEEK_CUR);
}
}
var.four[0] = fgetc(file);
var.four[1] = fgetc(file);
tmp = fgetc(file);
if(tmp==EOF) return -1;
var.four[2] = tmp;
if(var.four[2]&0x80)
{
var.four[3] = 0xff;
}
else
{
var.four[3] = 0x00;
}
if(var.one_signed > hdr->edfparam[channel].dig_max)
{
var.one_signed = hdr->edfparam[channel].dig_max;
}
else if(var.one_signed < hdr->edfparam[channel].dig_min)
{
var.one_signed = hdr->edfparam[channel].dig_min;
}
buf[i] = phys_bitvalue * (phys_offset + (double)var.one_signed);
sample_pntr++;
}
}
hdr->edfparam[channel].sample_pntr = sample_pntr;
return n;
}
int edfread_digital_samples(int handle, int edfsignal, int n, int *buf)
{
int bytes_per_smpl=2,
tmp,
i,
channel;
long long smp_in_file,
offset,
sample_pntr,
smp_per_record,
jump;
struct edfhdrblock *hdr;
union {
unsigned int one;
signed int one_signed;
unsigned short two[2];
signed short two_signed[2];
unsigned char four[4];
} var;
FILE *file;
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(edfsignal<0) return -1;
if(hdrlist[handle]->writemode) return -1;
if(edfsignal>=(hdrlist[handle]->edfsignals - hdrlist[handle]->nr_annot_chns)) return -1;
channel = hdrlist[handle]->mapped_signals[edfsignal];
if(n<0LL) return -1;
if(n==0LL) return 0LL;
hdr = hdrlist[handle];
if(hdr->edf)
{
bytes_per_smpl = 2;
}
if(hdr->bdf)
{
bytes_per_smpl = 3;
}
smp_in_file = hdr->edfparam[channel].smp_per_record * hdr->datarecords;
if((hdr->edfparam[channel].sample_pntr + n) > smp_in_file)
{
n = smp_in_file - hdr->edfparam[channel].sample_pntr;
if(n==0)
{
return 0LL;
}
if(n<0)
{
return -1;
}
}
file = hdr->file_hdl;
offset = hdr->hdrsize;
offset += (hdr->edfparam[channel].sample_pntr / hdr->edfparam[channel].smp_per_record) * hdr->recordsize;
offset += hdr->edfparam[channel].buf_offset;
offset += ((hdr->edfparam[channel].sample_pntr % hdr->edfparam[channel].smp_per_record) * bytes_per_smpl);
fseeko(file, offset, SEEK_SET);
sample_pntr = hdr->edfparam[channel].sample_pntr;
smp_per_record = hdr->edfparam[channel].smp_per_record;
jump = hdr->recordsize - (smp_per_record * bytes_per_smpl);
if(hdr->edf)
{
for(i=0; i<n; i++)
{
if(!(sample_pntr%smp_per_record))
{
if(i)
{
fseeko(file, jump, SEEK_CUR);
}
}
var.four[0] = fgetc(file);
tmp = fgetc(file);
if(tmp==EOF) return -1;
var.four[1] = tmp;
if(var.two_signed[0] > hdr->edfparam[channel].dig_max)
{
var.two_signed[0] = hdr->edfparam[channel].dig_max;
}
else if(var.two_signed[0] < hdr->edfparam[channel].dig_min)
{
var.two_signed[0] = hdr->edfparam[channel].dig_min;
}
buf[i] = var.two_signed[0];
sample_pntr++;
}
}
if(hdr->bdf)
{
for(i=0; i<n; i++)
{
if(!(sample_pntr%smp_per_record))
{
if(i)
{
fseeko(file, jump, SEEK_CUR);
}
}
var.four[0] = fgetc(file);
var.four[1] = fgetc(file);
tmp = fgetc(file);
if(tmp==EOF) return -1;
var.four[2] = tmp;
if(var.four[2]&0x80)
{
var.four[3] = 0xff;
}
else
{
var.four[3] = 0x00;
}
if(var.one_signed > hdr->edfparam[channel].dig_max)
{
var.one_signed = hdr->edfparam[channel].dig_max;
}
else if(var.one_signed < hdr->edfparam[channel].dig_min)
{
var.one_signed = hdr->edfparam[channel].dig_min;
}
buf[i] = var.one_signed;
sample_pntr++;
}
}
hdr->edfparam[channel].sample_pntr = sample_pntr;
return n;
}
int edf_get_annotation(int handle, int n, struct edf_annotation_struct *annot)
{
memset(annot, 0, sizeof(struct edf_annotation_struct));
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(hdrlist[handle]->writemode) return -1;
if(n<0) return -1;
if(n>=hdrlist[handle]->annots_in_file) return -1;
annot->onset = (annotationslist[handle] + n)->onset;
annot->duration_l = (annotationslist[handle] + n)->duration_l;
edflib_strlcpy(annot->duration, (annotationslist[handle] + n)->duration, 16);
edflib_strlcpy(annot->annotation, (annotationslist[handle] + n)->annotation, EDFLIB_MAX_ANNOTATION_LEN + 1);
return 0;
}
static struct edfhdrblock * edflib_check_edf_file(FILE *inputfile, int *edf_error)
{
int i, j, p, r=0, n,
dotposition,
error;
char *edf_hdr,
scratchpad[128],
scratchpad2[64];
struct edfhdrblock *edfhdr;
/***************** check header ******************************/
edf_hdr = (char *)calloc(1, 256);
if(edf_hdr==NULL)
{
*edf_error = EDFLIB_MALLOC_ERROR;
return NULL;
}
edfhdr = (struct edfhdrblock *)calloc(1, sizeof(struct edfhdrblock));
if(edfhdr==NULL)
{
free(edf_hdr);
*edf_error = EDFLIB_MALLOC_ERROR;
return NULL;
}
rewind(inputfile);
if(fread(edf_hdr, 256, 1, inputfile)!=1)
{
*edf_error = EDFLIB_FILE_READ_ERROR;
free(edf_hdr);
free(edfhdr);
return NULL;
}
/**************************** VERSION ***************************************/
strncpy(scratchpad, edf_hdr, 8);
scratchpad[8] = 0;
if(((signed char *)scratchpad)[0]==-1) /* BDF-file */
{
for(i=1; i<8; i++)
{
if((scratchpad[i]<32)||(scratchpad[i]>126))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
}
if(strcmp(scratchpad + 1, "BIOSEMI"))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
edfhdr->bdf = 1;
}
else /* EDF-file */
{
for(i=0; i<8; i++)
{
if((scratchpad[i]<32)||(scratchpad[i]>126))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
}
if(strcmp(scratchpad, "0 "))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
edfhdr->edf = 1;
}
strncpy(edfhdr->version, edf_hdr, 8);
edfhdr->version[8] = 0;
if(edfhdr->bdf) edfhdr->version[0] = '.';
/********************* PATIENTNAME *********************************************/
strncpy(scratchpad, edf_hdr + 8, 80);
scratchpad[80] = 0;
for(i=0; i<80; i++)
{
if((((unsigned char *)scratchpad)[i]<32)||(((unsigned char *)scratchpad)[i]>126))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
}
strncpy(edfhdr->patient, edf_hdr + 8, 80);
edfhdr->patient[80] = 0;
/********************* RECORDING *********************************************/
strncpy(scratchpad, edf_hdr + 88, 80);
scratchpad[80] = 0;
for(i=0; i<80; i++)
{
if((((unsigned char *)scratchpad)[i]<32)||(((unsigned char *)scratchpad)[i]>126))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
}
strncpy(edfhdr->recording, edf_hdr + 88, 80);
edfhdr->recording[80] = 0;
/********************* STARTDATE *********************************************/
strncpy(scratchpad, edf_hdr + 168, 8);
scratchpad[8] = 0;
for(i=0; i<8; i++)
{
if((scratchpad[i]<32)||(scratchpad[i]>126))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
}
error = 0;
if((edf_hdr[170]!='.')||(edf_hdr[173]!='.')) error = 1;
if((edf_hdr[168]<48)||(edf_hdr[168]>57)) error = 1;
if((edf_hdr[169]<48)||(edf_hdr[169]>57)) error = 1;
if((edf_hdr[171]<48)||(edf_hdr[171]>57)) error = 1;
if((edf_hdr[172]<48)||(edf_hdr[172]>57)) error = 1;
if((edf_hdr[174]<48)||(edf_hdr[174]>57)) error = 1;
if((edf_hdr[175]<48)||(edf_hdr[175]>57)) error = 1;
strncpy(scratchpad, edf_hdr + 168, 8);
if(error)
{
scratchpad[8] = 0;
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
scratchpad[2] = 0;
scratchpad[5] = 0;
scratchpad[8] = 0;
if((edflib_atoi_nonlocalized(scratchpad)<1)||(edflib_atoi_nonlocalized(scratchpad)>31))
{
strncpy(scratchpad, edf_hdr + 168, 8);
scratchpad[8] = 0;
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
if((edflib_atoi_nonlocalized(scratchpad+3)<1)||(edflib_atoi_nonlocalized(scratchpad+3)>12))
{
strncpy(scratchpad, edf_hdr + 168, 8);
scratchpad[8] = 0;
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
edfhdr->startdate_day = edflib_atoi_nonlocalized(scratchpad);
edfhdr->startdate_month = edflib_atoi_nonlocalized(scratchpad + 3);
edfhdr->startdate_year = edflib_atoi_nonlocalized(scratchpad + 6);
if(edfhdr->startdate_year>84)
{
edfhdr->startdate_year += 1900;
}
else
{
edfhdr->startdate_year += 2000;
}
/********************* STARTTIME *********************************************/
strncpy(scratchpad, edf_hdr + 176, 8);
scratchpad[8] = 0;
for(i=0; i<8; i++)
{
if((scratchpad[i]<32)||(scratchpad[i]>126))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
}
error = 0;
if((edf_hdr[178]!='.')||(edf_hdr[181]!='.')) error = 1;
if((edf_hdr[176]<48)||(edf_hdr[176]>57)) error = 1;
if((edf_hdr[177]<48)||(edf_hdr[177]>57)) error = 1;
if((edf_hdr[179]<48)||(edf_hdr[179]>57)) error = 1;
if((edf_hdr[180]<48)||(edf_hdr[180]>57)) error = 1;
if((edf_hdr[182]<48)||(edf_hdr[182]>57)) error = 1;
if((edf_hdr[183]<48)||(edf_hdr[183]>57)) error = 1;
strncpy(scratchpad, edf_hdr + 176, 8);
if(error)
{
strncpy(scratchpad, edf_hdr + 176, 8);
scratchpad[8] = 0;
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
scratchpad[2] = 0;
scratchpad[5] = 0;
scratchpad[8] = 0;
if(edflib_atoi_nonlocalized(scratchpad)>23)
{
strncpy(scratchpad, edf_hdr + 176, 8);
scratchpad[8] = 0;
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
if(edflib_atoi_nonlocalized(scratchpad+3)>59)
{
strncpy(scratchpad, edf_hdr + 176, 8);
scratchpad[8] = 0;
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
if(edflib_atoi_nonlocalized(scratchpad+6)>59)
{
strncpy(scratchpad, edf_hdr + 176, 8);
scratchpad[8] = 0;
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
edfhdr->starttime_hour = edflib_atoi_nonlocalized(scratchpad);
edfhdr->starttime_minute = edflib_atoi_nonlocalized(scratchpad + 3);
edfhdr->starttime_second = edflib_atoi_nonlocalized(scratchpad + 6);
edfhdr->l_starttime = 3600 * edflib_atoi_nonlocalized(scratchpad);
edfhdr->l_starttime += 60 * edflib_atoi_nonlocalized(scratchpad + 3);
edfhdr->l_starttime += edflib_atoi_nonlocalized(scratchpad + 6);
edfhdr->l_starttime *= EDFLIB_TIME_DIMENSION;
/***************** NUMBER OF SIGNALS IN HEADER *******************************/
strncpy(scratchpad, edf_hdr + 252, 4);
scratchpad[4] = 0;
for(i=0; i<4; i++)
{
if((scratchpad[i]<32)||(scratchpad[i]>126))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
}
if(edflib_is_integer_number(scratchpad))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
edfhdr->edfsignals = edflib_atoi_nonlocalized(scratchpad);
if(edfhdr->edfsignals<1)
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
if(edfhdr->edfsignals>EDFLIB_MAXSIGNALS)
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
/***************** NUMBER OF BYTES IN HEADER *******************************/
strncpy(scratchpad, edf_hdr + 184, 8);
scratchpad[8] = 0;
for(i=0; i<8; i++)
{
if((scratchpad[i]<32)||(scratchpad[i]>126))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
}
if(edflib_is_integer_number(scratchpad))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
n = edflib_atoi_nonlocalized(scratchpad);
if((edfhdr->edfsignals * 256 + 256)!=n)
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
/********************* RESERVED FIELD *************************************/
edfhdr->edfplus = 0;
edfhdr->discontinuous = 0;
strncpy(scratchpad, edf_hdr + 192, 44);
scratchpad[44] = 0;
for(i=0; i<44; i++)
{
if((scratchpad[i]<32)||(scratchpad[i]>126))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
}
if(edfhdr->edf)
{
if(!strncmp(scratchpad, "EDF+C", 5))
{
edfhdr->edfplus = 1;
}
if(!strncmp(scratchpad, "EDF+D", 5))
{
edfhdr->edfplus = 1;
edfhdr->discontinuous = 1;
}
}
if(edfhdr->bdf)
{
if(!strncmp(scratchpad, "BDF+C", 5))
{
edfhdr->bdfplus = 1;
}
if(!strncmp(scratchpad, "BDF+D", 5))
{
edfhdr->bdfplus = 1;
edfhdr->discontinuous = 1;
}
}
strncpy(edfhdr->reserved, edf_hdr + 192, 44);
edfhdr->reserved[44] = 0;
/********************* NUMBER OF DATARECORDS *************************************/
strncpy(scratchpad, edf_hdr + 236, 8);
scratchpad[8] = 0;
for(i=0; i<8; i++)
{
if((scratchpad[i]<32)||(scratchpad[i]>126))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
}
if(edflib_is_integer_number(scratchpad))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
edfhdr->datarecords = edflib_atoi_nonlocalized(scratchpad);
if(edfhdr->datarecords<1)
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
/********************* DATARECORD DURATION *************************************/
strncpy(scratchpad, edf_hdr + 244, 8);
scratchpad[8] = 0;
for(i=0; i<8; i++)
{
if((scratchpad[i]<32)||(scratchpad[i]>126))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
}
if(edflib_is_number(scratchpad))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
edfhdr->data_record_duration = edflib_atof_nonlocalized(scratchpad);
if(edfhdr->data_record_duration < -0.000001)
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr);
return NULL;
}
edfhdr->long_data_record_duration = edflib_get_long_duration(scratchpad);
free(edf_hdr);
/********************* START WITH THE SIGNALS IN THE HEADER *********************/
edf_hdr = (char *)calloc(1, (edfhdr->edfsignals + 1) * 256);
if(edf_hdr==NULL)
{
*edf_error = EDFLIB_MALLOC_ERROR;
free(edfhdr);
return NULL;
}
rewind(inputfile);
if(fread(edf_hdr, (edfhdr->edfsignals + 1) * 256, 1, inputfile)!=1)
{
*edf_error = EDFLIB_FILE_READ_ERROR;
free(edf_hdr);
free(edfhdr);
return NULL;
}
edfhdr->edfparam = (struct edfparamblock *)calloc(1, sizeof(struct edfparamblock) * edfhdr->edfsignals);
if(edfhdr->edfparam==NULL)
{
*edf_error = EDFLIB_MALLOC_ERROR;
free(edf_hdr);
free(edfhdr);
return NULL;
}
/**************************** LABELS *************************************/
edfhdr->nr_annot_chns = 0;
for(i=0; i<edfhdr->edfsignals; i++)
{
strncpy(scratchpad, edf_hdr + 256 + (i * 16), 16);
for(j=0; j<16; j++)
{
if((scratchpad[j]<32)||(scratchpad[j]>126))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
if(edfhdr->edfplus)
{
if(!strncmp(scratchpad, "EDF Annotations ", 16))
{
edfhdr->annot_ch[edfhdr->nr_annot_chns] = i;
edfhdr->nr_annot_chns++;
edfhdr->edfparam[i].annotation = 1;
}
}
if(edfhdr->bdfplus)
{
if(!strncmp(scratchpad, "BDF Annotations ", 16))
{
edfhdr->annot_ch[edfhdr->nr_annot_chns] = i;
edfhdr->nr_annot_chns++;
edfhdr->edfparam[i].annotation = 1;
}
}
strncpy(edfhdr->edfparam[i].label, edf_hdr + 256 + (i * 16), 16);
edfhdr->edfparam[i].label[16] = 0;
}
if(edfhdr->edfplus&&(!edfhdr->nr_annot_chns))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
if(edfhdr->bdfplus&&(!edfhdr->nr_annot_chns))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
if((edfhdr->edfsignals!=edfhdr->nr_annot_chns)||((!edfhdr->edfplus)&&(!edfhdr->bdfplus)))
{
if(edfhdr->data_record_duration<0.0000001)
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
/**************************** TRANSDUCER TYPES *************************************/
for(i=0; i<edfhdr->edfsignals; i++)
{
strncpy(scratchpad, edf_hdr + 256 + (edfhdr->edfsignals * 16) + (i * 80), 80);
for(j=0; j<80; j++)
{
if((scratchpad[j]<32)||(scratchpad[j]>126))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
strncpy(edfhdr->edfparam[i].transducer, edf_hdr + 256 + (edfhdr->edfsignals * 16) + (i * 80), 80);
edfhdr->edfparam[i].transducer[80] = 0;
if((edfhdr->edfplus) || (edfhdr->bdfplus))
{
if(edfhdr->edfparam[i].annotation)
{
for(j=0; j<80; j++)
{
if(edfhdr->edfparam[i].transducer[j]!=' ')
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
}
}
}
/**************************** PHYSICAL DIMENSIONS *************************************/
for(i=0; i<edfhdr->edfsignals; i++)
{
strncpy(scratchpad, edf_hdr + 256 + (edfhdr->edfsignals * 96) + (i * 8), 8);
for(j=0; j<8; j++)
{
if((scratchpad[j]<32)||(scratchpad[j]>126))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
strncpy(edfhdr->edfparam[i].physdimension, edf_hdr + 256 + (edfhdr->edfsignals * 96) + (i * 8), 8);
edfhdr->edfparam[i].physdimension[8] = 0;
}
/**************************** PHYSICAL MINIMUMS *************************************/
for(i=0; i<edfhdr->edfsignals; i++)
{
strncpy(scratchpad, edf_hdr + 256 + (edfhdr->edfsignals * 104) + (i * 8), 8);
scratchpad[8] = 0;
for(j=0; j<8; j++)
{
if((scratchpad[j]<32)||(scratchpad[j]>126))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
if(edflib_is_number(scratchpad))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
edfhdr->edfparam[i].phys_min = edflib_atof_nonlocalized(scratchpad);
}
/**************************** PHYSICAL MAXIMUMS *************************************/
for(i=0; i<edfhdr->edfsignals; i++)
{
strncpy(scratchpad, edf_hdr + 256 + (edfhdr->edfsignals * 112) + (i * 8), 8);
scratchpad[8] = 0;
for(j=0; j<8; j++)
{
if((scratchpad[j]<32)||(scratchpad[j]>126))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
if(edflib_is_number(scratchpad))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
edfhdr->edfparam[i].phys_max = edflib_atof_nonlocalized(scratchpad);
if(edfhdr->edfparam[i].phys_max==edfhdr->edfparam[i].phys_min)
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
/**************************** DIGITAL MINIMUMS *************************************/
for(i=0; i<edfhdr->edfsignals; i++)
{
strncpy(scratchpad, edf_hdr + 256 + (edfhdr->edfsignals * 120) + (i * 8), 8);
scratchpad[8] = 0;
for(j=0; j<8; j++)
{
if((scratchpad[j]<32)||(scratchpad[j]>126))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
if(edflib_is_integer_number(scratchpad))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
n = edflib_atoi_nonlocalized(scratchpad);
if(edfhdr->edfplus)
{
if(edfhdr->edfparam[i].annotation)
{
if(n!=-0x8000)
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
}
if(edfhdr->bdfplus)
{
if(edfhdr->edfparam[i].annotation)
{
if(n!=-0x800000)
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
}
if(edfhdr->edf)
{
if((n>0x7fff)||(n<-0x8000))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
if(edfhdr->bdf)
{
if((n>0x7fffff)||(n<-0x800000))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
edfhdr->edfparam[i].dig_min = n;
}
/**************************** DIGITAL MAXIMUMS *************************************/
for(i=0; i<edfhdr->edfsignals; i++)
{
strncpy(scratchpad, edf_hdr + 256 + (edfhdr->edfsignals * 128) + (i * 8), 8);
scratchpad[8] = 0;
for(j=0; j<8; j++)
{
if((scratchpad[j]<32)||(scratchpad[j]>126))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
if(edflib_is_integer_number(scratchpad))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
n = edflib_atoi_nonlocalized(scratchpad);
if(edfhdr->edfplus)
{
if(edfhdr->edfparam[i].annotation)
{
if(n!=0x7fff)
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
}
if(edfhdr->bdfplus)
{
if(edfhdr->edfparam[i].annotation)
{
if(n!=0x7fffff)
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
}
if(edfhdr->edf)
{
if((n>0x7fff)||(n<-0x8000))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
else
{
if((n>0x7fffff)||(n<-0x800000))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
edfhdr->edfparam[i].dig_max = n;
if(edfhdr->edfparam[i].dig_max<(edfhdr->edfparam[i].dig_min + 1))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
/**************************** PREFILTER FIELDS *************************************/
for(i=0; i<edfhdr->edfsignals; i++)
{
strncpy(scratchpad, edf_hdr + 256 + (edfhdr->edfsignals * 136) + (i * 80), 80);
for(j=0; j<80; j++)
{
if((scratchpad[j]<32)||(scratchpad[j]>126))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
strncpy(edfhdr->edfparam[i].prefilter, edf_hdr + 256 + (edfhdr->edfsignals * 136) + (i * 80), 80);
edfhdr->edfparam[i].prefilter[80] = 0;
if((edfhdr->edfplus) || (edfhdr->bdfplus))
{
if(edfhdr->edfparam[i].annotation)
{
for(j=0; j<80; j++)
{
if(edfhdr->edfparam[i].prefilter[j]!=' ')
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
}
}
}
/*********************** NR OF SAMPLES IN EACH DATARECORD ********************/
edfhdr->recordsize = 0;
for(i=0; i<edfhdr->edfsignals; i++)
{
strncpy(scratchpad, edf_hdr + 256 + (edfhdr->edfsignals * 216) + (i * 8), 8);
scratchpad[8] = 0;
for(j=0; j<8; j++)
{
if((scratchpad[j]<32)||(scratchpad[j]>126))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
if(edflib_is_integer_number(scratchpad))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
n = edflib_atoi_nonlocalized(scratchpad);
if(n<1)
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
edfhdr->edfparam[i].smp_per_record = n;
edfhdr->recordsize += n;
}
if(edfhdr->bdf)
{
edfhdr->recordsize *= 3;
if(edfhdr->recordsize > (15 * 1024 * 1024))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
else
{
edfhdr->recordsize *= 2;
if(edfhdr->recordsize > (10 * 1024 * 1024))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
/**************************** RESERVED FIELDS *************************************/
for(i=0; i<edfhdr->edfsignals; i++)
{
strncpy(scratchpad, edf_hdr + 256 + (edfhdr->edfsignals * 224) + (i * 32), 32);
for(j=0; j<32; j++)
{
if((scratchpad[j]<32)||(scratchpad[j]>126))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
strncpy(edfhdr->edfparam[i].reserved, edf_hdr + 256 + (edfhdr->edfsignals * 224) + (i * 32), 32);
edfhdr->edfparam[i].reserved[32] = 0;
}
/********************* EDF+ PATIENTNAME *********************************************/
if(edfhdr->edfplus || edfhdr->bdfplus)
{
error = 0;
dotposition = 0;
strncpy(scratchpad, edf_hdr + 8, 80);
scratchpad[80] = 0;
for(i=0; i<80; i++)
{
if(scratchpad[i]==' ')
{
dotposition = i;
break;
}
}
dotposition++;
if((dotposition>73)||(dotposition<2)) error = 1;
if(scratchpad[dotposition + 2]!='X')
{
if(dotposition>65) error = 1;
}
if((scratchpad[dotposition]!='M')&&(scratchpad[dotposition]!='F')&&(scratchpad[dotposition]!='X')) error = 1;
dotposition++;
if(scratchpad[dotposition]!=' ') error = 1;
if(scratchpad[dotposition + 1]=='X')
{
if(scratchpad[dotposition + 2]!=' ') error = 1;
if(scratchpad[dotposition + 3]==' ') error = 1;
}
else
{
if(scratchpad[dotposition + 12]!=' ') error = 1;
if(scratchpad[dotposition + 13]==' ') error = 1;
dotposition++;
strncpy(scratchpad2, scratchpad + dotposition, 11);
scratchpad2[11] = 0;
if((scratchpad2[2]!='-')||(scratchpad2[6]!='-')) error = 1;
scratchpad2[2] = 0;
scratchpad2[6] = 0;
if((scratchpad2[0]<48)||(scratchpad2[0]>57)) error = 1;
if((scratchpad2[1]<48)||(scratchpad2[1]>57)) error = 1;
if((scratchpad2[7]<48)||(scratchpad2[7]>57)) error = 1;
if((scratchpad2[8]<48)||(scratchpad2[8]>57)) error = 1;
if((scratchpad2[9]<48)||(scratchpad2[9]>57)) error = 1;
if((scratchpad2[10]<48)||(scratchpad2[10]>57)) error = 1;
if((edflib_atoi_nonlocalized(scratchpad2)<1)||(edflib_atoi_nonlocalized(scratchpad2)>31)) error = 1;
if(strcmp(scratchpad2 + 3, "JAN"))
if(strcmp(scratchpad2 + 3, "FEB"))
if(strcmp(scratchpad2 + 3, "MAR"))
if(strcmp(scratchpad2 + 3, "APR"))
if(strcmp(scratchpad2 + 3, "MAY"))
if(strcmp(scratchpad2 + 3, "JUN"))
if(strcmp(scratchpad2 + 3, "JUL"))
if(strcmp(scratchpad2 + 3, "AUG"))
if(strcmp(scratchpad2 + 3, "SEP"))
if(strcmp(scratchpad2 + 3, "OCT"))
if(strcmp(scratchpad2 + 3, "NOV"))
if(strcmp(scratchpad2 + 3, "DEC"))
error = 1;
}
if(error)
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
p = 0;
if((edfhdr->patient[p]=='X') && (edfhdr->patient[p+1]==' '))
{
edfhdr->plus_patientcode[0] = 0;
p += 2;
}
else
{
for(i=0; i<(80-p); i++)
{
if(edfhdr->patient[i+p]==' ')
{
break;
}
edfhdr->plus_patientcode[i] = edfhdr->patient[i+p];
if(edfhdr->plus_patientcode[i]=='_') edfhdr->plus_patientcode[i] = ' ';
}
edfhdr->plus_patientcode[i] = 0;
p += i + 1;
}
if(edfhdr->patient[p]=='M')
{
edflib_strlcpy(edfhdr->plus_gender, "Male", 16);
}
if(edfhdr->patient[p]=='F')
{
edflib_strlcpy(edfhdr->plus_gender, "Female", 16);
}
if(edfhdr->patient[p]=='X')
{
edfhdr->plus_gender[0] = 0;
}
for(i=0; i<(80-p);i++)
{
if(edfhdr->patient[i+p]==' ')
{
break;
}
}
p += i + 1;
if(edfhdr->patient[p]=='X')
{
edfhdr->plus_birthdate[0] = 0;
edfhdr->plus_birthdate_day = 0;
edfhdr->plus_birthdate_month = 0;
edfhdr->plus_birthdate_year = 0;
p += 2;
}
else
{
for(i=0; i<(80-p); i++)
{
if(edfhdr->patient[i+p]==' ')
{
break;
}
edfhdr->plus_birthdate[i] = edfhdr->patient[i+p];
}
edfhdr->plus_birthdate[2] = ' ';
edfhdr->plus_birthdate[3] += 32;
edfhdr->plus_birthdate[4] += 32;
edfhdr->plus_birthdate[5] += 32;
edfhdr->plus_birthdate[6] = ' ';
edfhdr->plus_birthdate[11] = 0;
p += i + 1;
edfhdr->plus_birthdate_day = edflib_atoi_nonlocalized(edfhdr->plus_birthdate);
if(!strncmp(edfhdr->plus_birthdate + 3, "jan", 3))
{
edfhdr->plus_birthdate_month = 1;
}
else if(!strncmp(edfhdr->plus_birthdate + 3, "feb", 3))
{
edfhdr->plus_birthdate_month = 2;
}
else if(!strncmp(edfhdr->plus_birthdate + 3, "mar", 3))
{
edfhdr->plus_birthdate_month = 3;
}
else if(!strncmp(edfhdr->plus_birthdate + 3, "apr", 3))
{
edfhdr->plus_birthdate_month = 4;
}
else if(!strncmp(edfhdr->plus_birthdate + 3, "may", 3))
{
edfhdr->plus_birthdate_month = 5;
}
else if(!strncmp(edfhdr->plus_birthdate + 3, "jun", 3))
{
edfhdr->plus_birthdate_month = 6;
}
else if(!strncmp(edfhdr->plus_birthdate + 3, "jul", 3))
{
edfhdr->plus_birthdate_month = 7;
}
else if(!strncmp(edfhdr->plus_birthdate + 3, "aug", 3))
{
edfhdr->plus_birthdate_month = 8;
}
else if(!strncmp(edfhdr->plus_birthdate + 3, "sep", 3))
{
edfhdr->plus_birthdate_month = 9;
}
else if(!strncmp(edfhdr->plus_birthdate + 3, "oct", 3))
{
edfhdr->plus_birthdate_month = 10;
}
else if(!strncmp(edfhdr->plus_birthdate + 3, "nov", 3))
{
edfhdr->plus_birthdate_month = 11;
}
else if(!strncmp(edfhdr->plus_birthdate + 3, "dec", 3))
{
edfhdr->plus_birthdate_month = 12;
}
else
{
edfhdr->plus_birthdate_month = 0;
}
edfhdr->plus_birthdate_year = edflib_atoi_nonlocalized(edfhdr->plus_birthdate + 7);
}
for(i=0; i<(80-p);i++)
{
if(edfhdr->patient[i+p]==' ')
{
break;
}
edfhdr->plus_patient_name[i] = edfhdr->patient[i+p];
if(edfhdr->plus_patient_name[i]=='_') edfhdr->plus_patient_name[i] = ' ';
}
edfhdr->plus_patient_name[i] = 0;
p += i + 1;
for(i=0; i<(80-p);i++)
{
edfhdr->plus_patient_additional[i] = edfhdr->patient[i+p];
}
edfhdr->plus_patient_additional[i] = 0;
p += i + 1;
}
/********************* EDF+ RECORDINGFIELD *********************************************/
if(edfhdr->edfplus || edfhdr->bdfplus)
{
error = 0;
strncpy(scratchpad, edf_hdr + 88, 80);
scratchpad[80] = 0;
if(strncmp(scratchpad, "Startdate ", 10)) error = 1;
if(scratchpad[10]=='X')
{
if(scratchpad[11]!=' ') error = 1;
if(scratchpad[12]==' ') error = 1;
p = 12;
}
else
{
if(scratchpad[21]!=' ') error = 1;
if(scratchpad[22]==' ') error = 1;
p = 22;
strncpy(scratchpad2, scratchpad + 10, 11);
scratchpad2[11] = 0;
if((scratchpad2[2]!='-')||(scratchpad2[6]!='-')) error = 1;
scratchpad2[2] = 0;
scratchpad2[6] = 0;
if((scratchpad2[0]<48)||(scratchpad2[0]>57)) error = 1;
if((scratchpad2[1]<48)||(scratchpad2[1]>57)) error = 1;
if((scratchpad2[7]<48)||(scratchpad2[7]>57)) error = 1;
if((scratchpad2[8]<48)||(scratchpad2[8]>57)) error = 1;
if((scratchpad2[9]<48)||(scratchpad2[9]>57)) error = 1;
if((scratchpad2[10]<48)||(scratchpad2[10]>57)) error = 1;
if((edflib_atoi_nonlocalized(scratchpad2)<1)||(edflib_atoi_nonlocalized(scratchpad2)>31)) error = 1;
r = 0;
if(!strcmp(scratchpad2 + 3, "JAN")) r = 1;
else if(!strcmp(scratchpad2 + 3, "FEB")) r = 2;
else if(!strcmp(scratchpad2 + 3, "MAR")) r = 3;
else if(!strcmp(scratchpad2 + 3, "APR")) r = 4;
else if(!strcmp(scratchpad2 + 3, "MAY")) r = 5;
else if(!strcmp(scratchpad2 + 3, "JUN")) r = 6;
else if(!strcmp(scratchpad2 + 3, "JUL")) r = 7;
else if(!strcmp(scratchpad2 + 3, "AUG")) r = 8;
else if(!strcmp(scratchpad2 + 3, "SEP")) r = 9;
else if(!strcmp(scratchpad2 + 3, "OCT")) r = 10;
else if(!strcmp(scratchpad2 + 3, "NOV")) r = 11;
else if(!strcmp(scratchpad2 + 3, "DEC")) r = 12;
else error = 1;
}
n = 0;
for(i=p; i<80; i++)
{
if(i>78)
{
error = 1;
break;
}
if(scratchpad[i]==' ')
{
n++;
if(scratchpad[i + 1]==' ')
{
error = 1;
break;
}
}
if(n>1) break;
}
if(error)
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
if(edf_hdr[98]!='X')
{
error = 0;
strncpy(scratchpad, edf_hdr + 168, 8);
scratchpad[2] = 0;
scratchpad[5] = 0;
scratchpad[8] = 0;
if(edflib_atoi_nonlocalized(scratchpad)!=edflib_atoi_nonlocalized(scratchpad2)) error = 1;
if(edflib_atoi_nonlocalized(scratchpad+3)!=r) error = 1;
if(edflib_atoi_nonlocalized(scratchpad+6)!=edflib_atoi_nonlocalized(scratchpad2+9)) error = 1;
if(error)
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
if(edfhdr->startdate_year != edflib_atoi_nonlocalized(scratchpad2 + 7))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
}
p = 10;
for(i=0; i<(80-p); i++)
{
if(edfhdr->recording[i+p]==' ')
{
break;
}
edfhdr->plus_startdate[i] = edfhdr->recording[i+p];
}
edfhdr->plus_startdate[2] = ' ';
edfhdr->plus_startdate[3] += 32;
edfhdr->plus_startdate[4] += 32;
edfhdr->plus_startdate[5] += 32;
edfhdr->plus_startdate[6] = ' ';
edfhdr->plus_startdate[11] = 0;
p += i + 1;
if((edfhdr->recording[p]=='X') && (edfhdr->recording[p+1]==' '))
{
edfhdr->plus_admincode[0] = 0;
p += 2;
}
else
{
for(i=0; i<(80-p); i++)
{
if(edfhdr->recording[i+p]==' ')
{
break;
}
edfhdr->plus_admincode[i] = edfhdr->recording[i+p];
if(edfhdr->plus_admincode[i]=='_') edfhdr->plus_admincode[i] = ' ';
}
edfhdr->plus_admincode[i] = 0;
p += i + 1;
}
if((edfhdr->recording[p]=='X') && (edfhdr->recording[p+1]==' '))
{
edfhdr->plus_technician[0] = 0;
p += 2;
}
else
{
for(i=0; i<(80-p); i++)
{
if(edfhdr->recording[i+p]==' ')
{
break;
}
edfhdr->plus_technician[i] = edfhdr->recording[i+p];
if(edfhdr->plus_technician[i]=='_') edfhdr->plus_technician[i] = ' ';
}
edfhdr->plus_technician[i] = 0;
p += i + 1;
}
if((edfhdr->recording[p]=='X') && (edfhdr->recording[p+1]==' '))
{
edfhdr->plus_equipment[0] = 0;
p += 2;
}
else
{
for(i=0; i<(80-p); i++)
{
if(edfhdr->recording[i+p]==' ')
{
break;
}
edfhdr->plus_equipment[i] = edfhdr->recording[i+p];
if(edfhdr->plus_equipment[i]=='_') edfhdr->plus_equipment[i] = ' ';
}
edfhdr->plus_equipment[i] = 0;
p += i + 1;
}
for(i=0; i<(80-p);i++)
{
edfhdr->plus_recording_additional[i] = edfhdr->recording[i+p];
}
edfhdr->plus_recording_additional[i] = 0;
p += i + 1;
}
/********************* FILESIZE *********************************************/
edfhdr->hdrsize = edfhdr->edfsignals * 256 + 256;
fseeko(inputfile, 0LL, SEEK_END);
if(ftello(inputfile)!=(edfhdr->recordsize * edfhdr->datarecords + edfhdr->hdrsize))
{
*edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
free(edf_hdr);
free(edfhdr->edfparam);
free(edfhdr);
return NULL;
}
n = 0;
for(i=0; i<edfhdr->edfsignals; i++)
{
edfhdr->edfparam[i].buf_offset = n;
if(edfhdr->bdf) n += edfhdr->edfparam[i].smp_per_record * 3;
else n += edfhdr->edfparam[i].smp_per_record * 2;
edfhdr->edfparam[i].bitvalue = (edfhdr->edfparam[i].phys_max - edfhdr->edfparam[i].phys_min) / (edfhdr->edfparam[i].dig_max - edfhdr->edfparam[i].dig_min);
edfhdr->edfparam[i].offset = edfhdr->edfparam[i].phys_max / edfhdr->edfparam[i].bitvalue - edfhdr->edfparam[i].dig_max;
}
edfhdr->file_hdl = inputfile;
free(edf_hdr);
return edfhdr;
}
static int edflib_is_integer_number(char *str)
{
int i=0, l, hasspace = 0, hassign=0, digit=0;
l = strlen(str);
if(!l) return 1;
if((str[0]=='+')||(str[0]=='-'))
{
hassign++;
i++;
}
for(; i<l; i++)
{
if(str[i]==' ')
{
if(!digit)
{
return 1;
}
hasspace++;
}
else
{
if((str[i]<48)||(str[i]>57))
{
return 1;
}
else
{
if(hasspace)
{
return 1;
}
digit++;
}
}
}
if(digit) return 0;
else return 1;
}
static int edflib_is_number(char *str)
{
int i=0, l, hasspace = 0, hassign=0, digit=0, hasdot=0, hasexp=0;
l = strlen(str);
if(!l) return 1;
if((str[0]=='+')||(str[0]=='-'))
{
hassign++;
i++;
}
for(; i<l; i++)
{
if((str[i]=='e')||(str[i]=='E'))
{
if((!digit)||hasexp)
{
return 1;
}
hasexp++;
hassign = 0;
digit = 0;
break;
}
if(str[i]==' ')
{
if(!digit)
{
return 1;
}
hasspace++;
}
else
{
if(((str[i]<48)||(str[i]>57))&&str[i]!='.')
{
return 1;
}
else
{
if(hasspace)
{
return 1;
}
if(str[i]=='.')
{
if(hasdot) return 1;
hasdot++;
}
else
{
digit++;
}
}
}
}
if(hasexp)
{
if(++i==l)
{
return 1;
}
if((str[i]=='+')||(str[i]=='-'))
{
hassign++;
i++;
}
for(; i<l; i++)
{
if(str[i]==' ')
{
if(!digit)
{
return 1;
}
hasspace++;
}
else
{
if((str[i]<48)||(str[i]>57))
{
return 1;
}
else
{
if(hasspace)
{
return 1;
}
digit++;
}
}
}
}
if(digit) return 0;
else return 1;
}
static long long edflib_get_long_duration(char *str)
{
int i, len=8, hasdot=0, dotposition=0;
long long value=0, radix;
if((str[0] == '+') || (str[0] == '-'))
{
for(i=0; i<7; i++)
{
str[i] = str[i+1];
}
str[7] = ' ';
}
for(i=0; i<8; i++)
{
if(str[i]==' ')
{
len = i;
break;
}
}
for(i=0; i<len; i++)
{
if(str[i]=='.')
{
hasdot = 1;
dotposition = i;
break;
}
}
if(hasdot)
{
radix = EDFLIB_TIME_DIMENSION;
for(i=dotposition-1; i>=0; i--)
{
value += ((long long)(str[i] - 48)) * radix;
radix *= 10;
}
radix = EDFLIB_TIME_DIMENSION / 10;
for(i=dotposition+1; i<len; i++)
{
value += ((long long)(str[i] - 48)) * radix;
radix /= 10;
}
}
else
{
radix = EDFLIB_TIME_DIMENSION;
for(i=len-1; i>=0; i--)
{
value += ((long long)(str[i] - 48)) * radix;
radix *= 10;
}
}
return value;
}
int edflib_version(void)
{
return EDFLIB_VERSION;
}
static int edflib_get_annotations(struct edfhdrblock *edfhdr, int hdl, int read_annotations_mode)
{
int i, j, k, p, r=0, n,
edfsignals,
datarecords,
recordsize,
discontinuous,
*annot_ch,
nr_annot_chns,
max,
onset,
duration,
duration_start,
zero,
max_tal_ln,
error,
annots_in_record,
annots_in_tal,
samplesize=2;
char *scratchpad,
*cnv_buf,
*time_in_txt,
*duration_in_txt;
long long data_record_duration,
elapsedtime,
time_tmp=0;
FILE *inputfile;
struct edfparamblock *edfparam;
struct edf_annotationblock *new_annotation=NULL,
*malloc_list;
inputfile = edfhdr->file_hdl;
edfsignals = edfhdr->edfsignals;
recordsize = edfhdr->recordsize;
edfparam = edfhdr->edfparam;
nr_annot_chns = edfhdr->nr_annot_chns;
datarecords = edfhdr->datarecords;
data_record_duration = edfhdr->long_data_record_duration;
discontinuous = edfhdr->discontinuous;
annot_ch = edfhdr->annot_ch;
if(edfhdr->edfplus)
{
samplesize = 2;
}
if(edfhdr->bdfplus)
{
samplesize = 3;
}
cnv_buf = (char *)calloc(1, recordsize);
if(cnv_buf==NULL)
{
return 1;
}
max_tal_ln = 0;
for(i=0; i<nr_annot_chns; i++)
{
if(max_tal_ln<edfparam[annot_ch[i]].smp_per_record * samplesize) max_tal_ln = edfparam[annot_ch[i]].smp_per_record * samplesize;
}
if(max_tal_ln<128) max_tal_ln = 128;
scratchpad = (char *)calloc(1, max_tal_ln + 3);
if(scratchpad==NULL)
{
free(cnv_buf);
return 1;
}
time_in_txt = (char *)calloc(1, max_tal_ln + 3);
if(time_in_txt==NULL)
{
free(cnv_buf);
free(scratchpad);
return 1;
}
duration_in_txt = (char *)calloc(1, max_tal_ln + 3);
if(duration_in_txt==NULL)
{
free(cnv_buf);
free(scratchpad);
free(time_in_txt);
return 1;
}
if(fseeko(inputfile, (long long)((edfsignals + 1) * 256), SEEK_SET))
{
free(cnv_buf);
free(scratchpad);
free(time_in_txt);
free(duration_in_txt);
return 2;
}
elapsedtime = 0;
for(i=0; i<datarecords; i++)
{
if(fread(cnv_buf, recordsize, 1, inputfile)!=1)
{
free(cnv_buf);
free(scratchpad);
free(time_in_txt);
free(duration_in_txt);
return 2;
}
/************** process annotationsignals (if any) **************/
error = 0;
for(r=0; r<nr_annot_chns; r++)
{
n = 0;
zero = 0;
onset = 0;
duration = 0;
duration_start = 0;
scratchpad[0] = 0;
annots_in_tal = 0;
annots_in_record = 0;
p = edfparam[annot_ch[r]].buf_offset;
max = edfparam[annot_ch[r]].smp_per_record * samplesize;
/************** process one annotation signal ****************/
if(cnv_buf[p + max - 1]!=0)
{
error = 5;
goto END;
}
if(!r) /* if it's the first annotation signal, then check */
{ /* the timekeeping annotation */
error = 1;
for(k=0; k<(max-2); k++)
{
scratchpad[k] = cnv_buf[p + k];
if(scratchpad[k]==20)
{
if(cnv_buf[p + k + 1]!=20)
{
error = 6;
goto END;
}
scratchpad[k] = 0;
if(edflib_is_onset_number(scratchpad))
{
error = 36;
goto END;
}
else
{
time_tmp = edflib_get_long_time(scratchpad);
if(i)
{
if(discontinuous)
{
if((time_tmp-elapsedtime)<data_record_duration)
{
error = 4;
goto END;
}
}
else
{
if((time_tmp-elapsedtime)!=data_record_duration)
{
error = 3;
goto END;
}
}
}
else
{
if((time_tmp>=EDFLIB_TIME_DIMENSION) || (time_tmp<0LL))
{
error = 2;
goto END;
}
else
{
edfhdr->starttime_offset = time_tmp;
if(read_annotations_mode==EDFLIB_DO_NOT_READ_ANNOTATIONS)
{
error = 0;
goto END_OUT;
}
}
}
elapsedtime = time_tmp;
error = 0;
break;
}
}
}
}
for(k=0; k<max; k++)
{
scratchpad[n] = cnv_buf[p + k];
if(!scratchpad[n])
{
if(!zero)
{
if(k)
{
if(cnv_buf[p + k - 1]!=20)
{
error = 33;
goto END;
}
}
n = 0;
onset = 0;
duration = 0;
duration_start = 0;
scratchpad[0] = 0;
annots_in_tal = 0;
}
zero++;
continue;
}
if(zero>1)
{
error = 34;
goto END;
}
zero = 0;
if((scratchpad[n]==20)||(scratchpad[n]==21))
{
if(scratchpad[n]==21)
{
if(duration||duration_start||onset||annots_in_tal)
{ /* it's not allowed to have multiple duration fields */
error = 35; /* in one TAL or to have a duration field which is */
goto END; /* not immediately behind the onsetfield */
}
duration_start = 1;
}
if((scratchpad[n]==20)&&onset&&(!duration_start))
{
if(r||annots_in_record)
{
if(n >= 0)
{
if(edfhdr->annots_in_file >= edfhdr->annotlist_sz)
{
malloc_list = (struct edf_annotationblock *)realloc(annotationslist[hdl],
sizeof(struct edf_annotationblock) * (edfhdr->annotlist_sz + EDFLIB_ANNOT_MEMBLOCKSZ));
if(malloc_list==NULL)
{
free(cnv_buf);
free(scratchpad);
free(time_in_txt);
free(duration_in_txt);
return -1;
}
annotationslist[hdl] = malloc_list;
edfhdr->annotlist_sz += EDFLIB_ANNOT_MEMBLOCKSZ;
}
new_annotation = annotationslist[hdl] + edfhdr->annots_in_file;
new_annotation->annotation[0] = 0;
if(duration)
{
edflib_strlcpy(new_annotation->duration, duration_in_txt, 16);
new_annotation->duration_l = edflib_get_long_time(duration_in_txt);
}
else
{
new_annotation->duration[0] = 0;
new_annotation->duration_l = -EDFLIB_TIME_DIMENSION;
}
for(j=0; j<n; j++)
{
if(j==EDFLIB_MAX_ANNOTATION_LEN) break;
new_annotation->annotation[j] = scratchpad[j];
}
new_annotation->annotation[j] = 0;
new_annotation->onset = edflib_get_long_time(time_in_txt);
new_annotation->onset -= edfhdr->starttime_offset;
edfhdr->annots_in_file++;
if(read_annotations_mode==EDFLIB_READ_ANNOTATIONS)
{
if(!(strncmp(new_annotation->annotation, "Recording ends", 14)))
{
if(nr_annot_chns==1)
{
goto END;
}
}
}
}
}
annots_in_tal++;
annots_in_record++;
n = 0;
continue;
}
if(!onset)
{
scratchpad[n] = 0;
if(edflib_is_onset_number(scratchpad))
{
error = 36;
goto END;
}
onset = 1;
n = 0;
edflib_strlcpy(time_in_txt, scratchpad, max_tal_ln + 3);
continue;
}
if(duration_start)
{
scratchpad[n] = 0;
if(edflib_is_duration_number(scratchpad))
{
error = 37;
goto END;
}
for(j=0; j<n; j++)
{
if(j==15) break;
duration_in_txt[j] = scratchpad[j];
if((duration_in_txt[j]<32)||(duration_in_txt[j]>126))
{
duration_in_txt[j] = '.';
}
}
duration_in_txt[j] = 0;
duration = 1;
duration_start = 0;
n = 0;
continue;
}
}
n++;
}
END:
/****************** end ************************/
if(error)
{
free(cnv_buf);
free(scratchpad);
free(time_in_txt);
free(duration_in_txt);
return 9;
}
}
}
END_OUT:
free(cnv_buf);
free(scratchpad);
free(time_in_txt);
free(duration_in_txt);
return 0;
}
static int edflib_is_duration_number(char *str)
{
int i, l, hasdot = 0;
l = strlen(str);
if(!l) return 1;
if((str[0] == '.')||(str[l-1] == '.')) return 1;
for(i=0; i<l; i++)
{
if(str[i]=='.')
{
if(hasdot) return 1;
hasdot++;
}
else
{
if((str[i]<48)||(str[i]>57)) return 1;
}
}
return 0;
}
static int edflib_is_onset_number(char *str)
{
int i, l, hasdot = 0;
l = strlen(str);
if(l<2) return 1;
if((str[0]!='+')&&(str[0]!='-')) return 1;
if((str[1] == '.')||(str[l-1] == '.')) return 1;
for(i=1; i<l; i++)
{
if(str[i]=='.')
{
if(hasdot) return 1;
hasdot++;
}
else
{
if((str[i]<48)||(str[i]>57)) return 1;
}
}
return 0;
}
static long long edflib_get_long_time(char *str)
{
int i, len, hasdot=0, dotposition=0, neg=0;
long long value=0, radix;
if(str[0] == '+')
{
str++;
}
else if(str[0] == '-')
{
neg = 1;
str++;
}
len = strlen(str);
for(i=0; i<len; i++)
{
if(str[i]=='.')
{
hasdot = 1;
dotposition = i;
break;
}
}
if(hasdot)
{
radix = EDFLIB_TIME_DIMENSION;
for(i=dotposition-1; i>=0; i--)
{
value += ((long long)(str[i] - 48)) * radix;
radix *= 10;
}
radix = EDFLIB_TIME_DIMENSION / 10;
for(i=dotposition+1; i<len; i++)
{
value += ((long long)(str[i] - 48)) * radix;
radix /= 10;
}
}
else
{
radix = EDFLIB_TIME_DIMENSION;
for(i=len-1; i>=0; i--)
{
value += ((long long)(str[i] - 48)) * radix;
radix *= 10;
}
}
if(neg) value = -value;
return value;
}
static void edflib_latin1_to_ascii(char *str, int len)
{
/* ISO 8859-1 except for characters 0x80 to 0x9f which are taken from the extension CP-1252 */
int i, value;
const char conv_table[]=".E.,F\".++^.S<E.Z..`\'\"\".--~.s>e.zY.i....|....<...-....\'u.....>...?AAAAAAECEEEEIIIIDNOOOOOxOUUUUYtsaaaaaaeceeeeiiiidnooooo:0uuuuyty";
for(i=0; i<len; i++)
{
value = *((unsigned char *)(str + i));
if((value>31)&&(value<127))
{
continue;
}
if(value < 32)
{
str[i] = '.';
continue;
}
str[i] = conv_table[value - 127];
}
}
static void edflib_latin12utf8(char *latin1_str, int len)
{
int i, j;
unsigned char *str, tmp_str[512];
str = (unsigned char *)latin1_str;
j = 0;
for(i=0; i<len; i++)
{
if(str[i]==0)
{
tmp_str[j] = 0;
break;
}
tmp_str[j] = str[i];
if(str[i]<32) tmp_str[j] = '.';
if((str[i]>126)&&(str[i]<160)) tmp_str[j] = '.';
if(str[i]>159)
{
if((len-j)<2)
{
tmp_str[j] = ' ';
}
else
{
tmp_str[j] = 192 + (str[i]>>6);
j++;
tmp_str[j] = 128 + (str[i]&63);
}
}
j++;
if(j>=len) break;
}
for(i=0; i<len; i++)
{
str[i] = tmp_str[i];
}
}
int edfopen_file_writeonly_with_params(const char *path, int filetype, int number_of_signals, int samplefrequency, double phys_max_min, const char *phys_dim)
{
int i, handle;
char str[32]="";
handle = edfopen_file_writeonly(path, filetype, number_of_signals);
if(handle < 0)
{
return handle;
}
for(i=0; i<number_of_signals; i++)
{
if(edf_set_samplefrequency(handle, i, samplefrequency))
{
edfclose_file(handle);
return -1;
}
if(edf_set_physical_maximum(handle, i, phys_max_min))
{
edfclose_file(handle);
return -1;
}
if(edf_set_physical_minimum(handle, i, -phys_max_min))
{
edfclose_file(handle);
return -1;
}
if(edf_set_physical_dimension(handle, i, phys_dim))
{
edfclose_file(handle);
return -1;
}
snprintf(str, 32, "chan. %i", i + 1);
if(edf_set_label(handle, i, str))
{
edfclose_file(handle);
return -1;
}
if(filetype == EDFLIB_FILETYPE_BDFPLUS)
{
if(edf_set_digital_maximum(handle, i, 0x7fffff))
{
edfclose_file(handle);
return -1;
}
if(edf_set_digital_minimum(handle, i, -0x800000))
{
edfclose_file(handle);
return -1;
}
}
else
{
if(edf_set_digital_maximum(handle, i, 0x7fff))
{
edfclose_file(handle);
return -1;
}
if(edf_set_digital_minimum(handle, i, -0x8000))
{
edfclose_file(handle);
return -1;
}
}
}
return handle;
}
int edfopen_file_writeonly(const char *path, int filetype, int number_of_signals)
{
int i, handle;
FILE *file;
struct edfhdrblock *hdr;
union
{
char four[4];
int one;
} byte_order_test_var;
/* avoid surprises! */
if((sizeof(char) != 1) ||
(sizeof(short) != 2) ||
(sizeof(int) != 4) ||
(sizeof(long long) != 8) ||
(sizeof(float) != 4) ||
(sizeof(double) != 8))
{
return EDFLIB_ARCH_ERROR;
}
/* check endianness! */
byte_order_test_var.one = 0x03020100;
if((byte_order_test_var.four[0] != 0) ||
(byte_order_test_var.four[1] != 1) ||
(byte_order_test_var.four[2] != 2) ||
(byte_order_test_var.four[3] != 3))
{
return EDFLIB_ARCH_ERROR;
}
if((filetype!=EDFLIB_FILETYPE_EDFPLUS)&&(filetype!=EDFLIB_FILETYPE_BDFPLUS))
{
return EDFLIB_FILETYPE_ERROR;
}
if(edf_files_open>=EDFLIB_MAXFILES)
{
return EDFLIB_MAXFILES_REACHED;
}
for(i=0; i<EDFLIB_MAXFILES; i++)
{
if(hdrlist[i]!=NULL)
{
if(!(strcmp(path, hdrlist[i]->path)))
{
return EDFLIB_FILE_ALREADY_OPENED;
}
}
}
if(number_of_signals<0)
{
return EDFLIB_NUMBER_OF_SIGNALS_INVALID;
}
if(number_of_signals>EDFLIB_MAXSIGNALS)
{
return EDFLIB_NUMBER_OF_SIGNALS_INVALID;
}
hdr = (struct edfhdrblock *)calloc(1, sizeof(struct edfhdrblock));
if(hdr==NULL)
{
return EDFLIB_MALLOC_ERROR;
}
hdr->edfparam = (struct edfparamblock *)calloc(1, sizeof(struct edfparamblock) * number_of_signals);
if(hdr->edfparam==NULL)
{
free(hdr);
return EDFLIB_MALLOC_ERROR;
}
hdr->writemode = 1;
hdr->edfsignals = number_of_signals;
handle = -1;
for(i=0; i<EDFLIB_MAXFILES; i++)
{
if(hdrlist[i]==NULL)
{
hdrlist[i] = hdr;
handle = i;
break;
}
}
if(handle<0)
{
free(hdr->edfparam);
free(hdr);
return EDFLIB_MAXFILES_REACHED;
}
write_annotationslist[handle] = NULL;
hdr->annotlist_sz = 0;
hdr->annots_in_file = 0;
file = fopeno(path, "wb");
if(file==NULL)
{
free(hdr->edfparam);
hdr->edfparam = NULL;
free(hdr);
hdr = NULL;
hdrlist[handle] = NULL;
return EDFLIB_NO_SUCH_FILE_OR_DIRECTORY;
}
hdr->file_hdl = file;
edflib_strlcpy(hdr->path, path, 1024);
edf_files_open++;
if(filetype==EDFLIB_FILETYPE_EDFPLUS)
{
hdr->edf = 1;
hdr->edfplus = 1;
}
if(filetype==EDFLIB_FILETYPE_BDFPLUS)
{
hdr->bdf = 1;
hdr->bdfplus = 1;
}
hdr->long_data_record_duration = EDFLIB_TIME_DIMENSION;
hdr->data_record_duration = 1.0;
hdr->nr_annot_chns = 1;
return handle;
}
int edf_set_samplefrequency(int handle, int edfsignal, int samplefrequency)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(edfsignal<0) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(edfsignal>=hdrlist[handle]->edfsignals) return -1;
if(samplefrequency<1) return -1;
if(hdrlist[handle]->datarecords) return -1;
hdrlist[handle]->edfparam[edfsignal].smp_per_record = samplefrequency;
return 0;
}
int edf_set_number_of_annotation_signals(int handle, int annot_signals)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
if((annot_signals < 1) || (annot_signals > EDFLIB_MAX_ANNOTATION_CHANNELS)) return -1;
hdrlist[handle]->nr_annot_chns = annot_signals;
return 0;
}
int edf_set_datarecord_duration(int handle, int duration)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
if((duration < 100) || (duration > 6000000)) return -1;
hdrlist[handle]->long_data_record_duration = (long long)duration * 100LL;
if(hdrlist[handle]->long_data_record_duration < (EDFLIB_TIME_DIMENSION * 10LL))
{
hdrlist[handle]->long_data_record_duration /= 10LL;
hdrlist[handle]->long_data_record_duration *= 10LL;
}
else
{
hdrlist[handle]->long_data_record_duration /= 100LL;
hdrlist[handle]->long_data_record_duration *= 100LL;
}
hdrlist[handle]->data_record_duration = ((double)(hdrlist[handle]->long_data_record_duration)) / EDFLIB_TIME_DIMENSION;
return 0;
}
int edf_set_micro_datarecord_duration(int handle, int duration)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
if((duration < 1) || (duration > 9999)) return -1;
hdrlist[handle]->long_data_record_duration = (long long)duration * 10LL;
hdrlist[handle]->data_record_duration = ((double)(hdrlist[handle]->long_data_record_duration)) / EDFLIB_TIME_DIMENSION;
return 0;
}
int edf_set_subsecond_starttime(int handle, int subsecond)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
if((subsecond < 0) || (subsecond > 9999999)) return -1;
hdrlist[handle]->starttime_offset = (long long)subsecond;
return 0;
}
int edfwrite_digital_short_samples(int handle, short *buf)
{
int i,
error,
sf,
digmax,
digmin,
edfsignal,
value;
FILE *file;
struct edfhdrblock *hdr;
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->edfsignals == 0) return -1;
if(hdrlist[handle]->bdf == 1) return -1;
hdr = hdrlist[handle];
file = hdr->file_hdl;
edfsignal = hdr->signal_write_sequence_pos;
if(!hdr->datarecords)
{
if(!edfsignal)
{
error = edflib_write_edf_header(hdr);
if(error) return error;
}
}
sf = hdr->edfparam[edfsignal].smp_per_record;
digmax = hdr->edfparam[edfsignal].dig_max;
digmin = hdr->edfparam[edfsignal].dig_min;
if(hdr->edf)
{
if((digmax != 0x7fff) || (digmin != -0x8000))
{
for(i=0; i<sf; i++)
{
if(buf[i]>digmax) buf[i] = digmax;
if(buf[i]<digmin) buf[i] = digmin;
}
}
if(fwrite(buf, sf * 2, 1, file) != 1) return -1;
}
else // BDF
{
if(hdr->wrbufsize < (sf * 3))
{
free(hdr->wrbuf);
hdr->wrbufsize = 0;
hdr->wrbuf = (char *)malloc(sf * 3);
if(hdr->wrbuf == NULL) return -1;
hdr->wrbufsize = sf * 3;
}
for(i=0; i<sf; i++)
{
value = buf[i];
if(value>digmax) value = digmax;
if(value<digmin) value = digmin;
hdr->wrbuf[i * 3] = value & 0xff;
hdr->wrbuf[i * 3 + 1] = (value >> 8) & 0xff;
hdr->wrbuf[i * 3 + 2] = (value >> 16) & 0xff;
}
if(fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) return -1;
}
hdr->signal_write_sequence_pos++;
if(hdr->signal_write_sequence_pos == hdr->edfsignals)
{
hdr->signal_write_sequence_pos = 0;
if(edflib_write_tal(hdr, file)) return -1;
hdr->datarecords++;
fflush(file);
}
return 0;
}
int edfwrite_digital_samples(int handle, int *buf)
{
int i,
error,
sf,
digmax,
digmin,
edfsignal,
value;
FILE *file;
struct edfhdrblock *hdr;
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->edfsignals == 0) return -1;
hdr = hdrlist[handle];
file = hdr->file_hdl;
edfsignal = hdr->signal_write_sequence_pos;
if(!hdr->datarecords)
{
if(!edfsignal)
{
error = edflib_write_edf_header(hdr);
if(error) return error;
}
}
sf = hdr->edfparam[edfsignal].smp_per_record;
digmax = hdr->edfparam[edfsignal].dig_max;
digmin = hdr->edfparam[edfsignal].dig_min;
if(hdr->edf)
{
if(hdr->wrbufsize < (sf * 2))
{
free(hdr->wrbuf);
hdr->wrbufsize = 0;
hdr->wrbuf = (char *)malloc(sf * 2);
if(hdr->wrbuf == NULL) return -1;
hdr->wrbufsize = sf * 2;
}
for(i=0; i<sf; i++)
{
value = buf[i];
if(value>digmax) value = digmax;
if(value<digmin) value = digmin;
hdr->wrbuf[i * 2] = value & 0xff;
hdr->wrbuf[i * 2 + 1] = (value >> 8) & 0xff;
}
if(fwrite(hdr->wrbuf, sf * 2, 1, file) != 1) return -1;
}
else // BDF
{
if(hdr->wrbufsize < (sf * 3))
{
free(hdr->wrbuf);
hdr->wrbufsize = 0;
hdr->wrbuf = (char *)malloc(sf * 3);
if(hdr->wrbuf == NULL) return -1;
hdr->wrbufsize = sf * 3;
}
for(i=0; i<sf; i++)
{
value = buf[i];
if(value>digmax) value = digmax;
if(value<digmin) value = digmin;
hdr->wrbuf[i * 3] = value & 0xff;
hdr->wrbuf[i * 3 + 1] = (value >> 8) & 0xff;
hdr->wrbuf[i * 3 + 2] = (value >> 16) & 0xff;
}
if(fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) return -1;
}
hdr->signal_write_sequence_pos++;
if(hdr->signal_write_sequence_pos == hdr->edfsignals)
{
hdr->signal_write_sequence_pos = 0;
if(edflib_write_tal(hdr, file)) return -1;
hdr->datarecords++;
fflush(file);
}
return 0;
}
int edf_blockwrite_digital_samples(int handle, int *buf)
{
int i, j,
error,
sf,
digmax,
digmin,
edfsignals,
buf_offset,
value;
FILE *file;
struct edfhdrblock *hdr;
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->edfsignals == 0) return -1;
if(hdrlist[handle]->signal_write_sequence_pos) return -1;
hdr = hdrlist[handle];
file = hdr->file_hdl;
edfsignals = hdr->edfsignals;
if(!hdr->datarecords)
{
error = edflib_write_edf_header(hdr);
if(error) return error;
}
buf_offset = 0;
for(j=0; j<edfsignals; j++)
{
sf = hdr->edfparam[j].smp_per_record;
digmax = hdr->edfparam[j].dig_max;
digmin = hdr->edfparam[j].dig_min;
if(hdr->edf)
{
if(hdr->wrbufsize < (sf * 2))
{
free(hdr->wrbuf);
hdr->wrbufsize = 0;
hdr->wrbuf = (char *)malloc(sf * 2);
if(hdr->wrbuf == NULL) return -1;
hdr->wrbufsize = sf * 2;
}
for(i=0; i<sf; i++)
{
value = buf[i + buf_offset];
if(value>digmax) value = digmax;
if(value<digmin) value = digmin;
hdr->wrbuf[i * 2] = value & 0xff;
hdr->wrbuf[i * 2 + 1] = (value >> 8) & 0xff;
}
if(fwrite(hdr->wrbuf, sf * 2, 1, file) != 1) return -1;
}
else // BDF
{
if(hdr->wrbufsize < (sf * 3))
{
free(hdr->wrbuf);
hdr->wrbufsize = 0;
hdr->wrbuf = (char *)malloc(sf * 3);
if(hdr->wrbuf == NULL) return -1;
hdr->wrbufsize = sf * 3;
}
for(i=0; i<sf; i++)
{
value = buf[i + buf_offset];
if(value>digmax) value = digmax;
if(value<digmin) value = digmin;
hdr->wrbuf[i * 3] = value & 0xff;
hdr->wrbuf[i * 3 + 1] = (value >> 8) & 0xff;
hdr->wrbuf[i * 3 + 2] = (value >> 16) & 0xff;
}
if(fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) return -1;
}
buf_offset += sf;
}
if(edflib_write_tal(hdr, file)) return -1;
hdr->datarecords++;
fflush(file);
return 0;
}
int edf_blockwrite_digital_short_samples(int handle, short *buf)
{
int i, j,
error,
sf,
digmax,
digmin,
edfsignals,
buf_offset,
value;
FILE *file;
struct edfhdrblock *hdr;
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->edfsignals == 0) return -1;
if(hdrlist[handle]->signal_write_sequence_pos) return -1;
if(hdrlist[handle]->bdf == 1) return -1;
hdr = hdrlist[handle];
file = hdr->file_hdl;
edfsignals = hdr->edfsignals;
if(!hdr->datarecords)
{
error = edflib_write_edf_header(hdr);
if(error)
{
return error;
}
}
buf_offset = 0;
for(j=0; j<edfsignals; j++)
{
sf = hdr->edfparam[j].smp_per_record;
digmax = hdr->edfparam[j].dig_max;
digmin = hdr->edfparam[j].dig_min;
if(hdr->edf)
{
if((digmax != 0x7fff) || (digmin != -0x8000))
{
for(i=0; i<sf; i++)
{
if(buf[i + buf_offset] > digmax)
{
buf[i + buf_offset] = digmax;
}
if(buf[i + buf_offset] < digmin)
{
buf[i + buf_offset] = digmin;
}
}
}
if(fwrite(buf + buf_offset, sf * 2, 1, file) != 1) return -1;
}
else // BDF
{
if(hdr->wrbufsize < (sf * 3))
{
free(hdr->wrbuf);
hdr->wrbufsize = 0;
hdr->wrbuf = (char *)malloc(sf * 3);
if(hdr->wrbuf == NULL) return -1;
hdr->wrbufsize = sf * 3;
}
for(i=0; i<sf; i++)
{
value = buf[i + buf_offset];
if(value>digmax) value = digmax;
if(value<digmin) value = digmin;
hdr->wrbuf[i * 3] = value & 0xff;
hdr->wrbuf[i * 3 + 1] = (value >> 8) & 0xff;
hdr->wrbuf[i * 3 + 2] = (value >> 16) & 0xff;
}
if(fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) return -1;
}
buf_offset += sf;
}
if(edflib_write_tal(hdr, file)) return -1;
hdr->datarecords++;
fflush(file);
return 0;
}
int edf_blockwrite_digital_3byte_samples(int handle, void *buf)
{
int j,
error,
edfsignals,
total_samples=0;
FILE *file;
struct edfhdrblock *hdr;
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->edfsignals == 0) return -1;
if(hdrlist[handle]->signal_write_sequence_pos) return -1;
if(hdrlist[handle]->bdf != 1) return -1;
hdr = hdrlist[handle];
file = hdr->file_hdl;
edfsignals = hdr->edfsignals;
if(!hdr->datarecords)
{
error = edflib_write_edf_header(hdr);
if(error) return error;
}
for(j=0; j<edfsignals; j++)
{
total_samples += hdr->edfparam[j].smp_per_record;
}
if(fwrite(buf, total_samples * 3, 1, file) != 1) return -1;
if(edflib_write_tal(hdr, file)) return -1;
hdr->datarecords++;
fflush(file);
return 0;
}
int edfwrite_physical_samples(int handle, double *buf)
{
int i,
error,
sf,
digmax,
digmin,
value,
edfsignal;
double bitvalue,
phys_offset;
FILE *file;
struct edfhdrblock *hdr;
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->edfsignals == 0) return -1;
hdr = hdrlist[handle];
file = hdr->file_hdl;
edfsignal = hdr->signal_write_sequence_pos;
if(!hdr->datarecords)
{
if(!edfsignal)
{
error = edflib_write_edf_header(hdr);
if(error) return error;
}
}
sf = hdr->edfparam[edfsignal].smp_per_record;
digmax = hdr->edfparam[edfsignal].dig_max;
digmin = hdr->edfparam[edfsignal].dig_min;
bitvalue = hdr->edfparam[edfsignal].bitvalue;
phys_offset = hdr->edfparam[edfsignal].offset;
if(hdr->edf)
{
if(hdr->wrbufsize < (sf * 2))
{
free(hdr->wrbuf);
hdr->wrbufsize = 0;
hdr->wrbuf = (char *)malloc(sf * 2);
if(hdr->wrbuf == NULL) return -1;
hdr->wrbufsize = sf * 2;
}
for(i=0; i<sf; i++)
{
value = (buf[i] / bitvalue) - phys_offset;
if(value>digmax) value = digmax;
if(value<digmin) value = digmin;
hdr->wrbuf[i * 2] = value & 0xff;
hdr->wrbuf[i * 2 + 1] = (value >> 8) & 0xff;
}
if(fwrite(hdr->wrbuf, sf * 2, 1, file) != 1) return -1;
}
else // BDF
{
if(hdr->wrbufsize < (sf * 3))
{
free(hdr->wrbuf);
hdr->wrbufsize = 0;
hdr->wrbuf = (char *)malloc(sf * 3);
if(hdr->wrbuf == NULL) return -1;
hdr->wrbufsize = sf * 3;
}
for(i=0; i<sf; i++)
{
value = (buf[i] / bitvalue) - phys_offset;
if(value>digmax) value = digmax;
if(value<digmin) value = digmin;
hdr->wrbuf[i * 3] = value & 0xff;
hdr->wrbuf[i * 3 + 1] = (value >> 8) & 0xff;
hdr->wrbuf[i * 3 + 2] = (value >> 16) & 0xff;
}
if(fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) return -1;
}
hdr->signal_write_sequence_pos++;
if(hdr->signal_write_sequence_pos == hdr->edfsignals)
{
hdr->signal_write_sequence_pos = 0;
if(edflib_write_tal(hdr, file)) return -1;
hdr->datarecords++;
fflush(file);
}
return 0;
}
int edf_blockwrite_physical_samples(int handle, double *buf)
{
int i, j,
error,
sf,
digmax,
digmin,
edfsignals,
buf_offset,
value;
double bitvalue,
phys_offset;
FILE *file;
struct edfhdrblock *hdr;
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->edfsignals == 0) return -1;
if(hdrlist[handle]->signal_write_sequence_pos) return -1;
hdr = hdrlist[handle];
file = hdr->file_hdl;
edfsignals = hdr->edfsignals;
if(!hdr->datarecords)
{
error = edflib_write_edf_header(hdr);
if(error) return error;
}
buf_offset = 0;
for(j=0; j<edfsignals; j++)
{
sf = hdr->edfparam[j].smp_per_record;
digmax = hdr->edfparam[j].dig_max;
digmin = hdr->edfparam[j].dig_min;
bitvalue = hdr->edfparam[j].bitvalue;
phys_offset = hdr->edfparam[j].offset;
if(hdr->edf)
{
if(hdr->wrbufsize < (sf * 2))
{
free(hdr->wrbuf);
hdr->wrbufsize = 0;
hdr->wrbuf = (char *)malloc(sf * 2);
if(hdr->wrbuf == NULL) return -1;
hdr->wrbufsize = sf * 2;
}
for(i=0; i<sf; i++)
{
value = (buf[i + buf_offset] / bitvalue) - phys_offset;
if(value>digmax) value = digmax;
if(value<digmin) value = digmin;
hdr->wrbuf[i * 2] = value & 0xff;
hdr->wrbuf[i * 2 + 1] = (value >> 8) & 0xff;
}
if(fwrite(hdr->wrbuf, sf * 2, 1, file) != 1) return -1;
}
else // BDF
{
if(hdr->wrbufsize < (sf * 3))
{
free(hdr->wrbuf);
hdr->wrbufsize = 0;
hdr->wrbuf = (char *)malloc(sf * 3);
if(hdr->wrbuf == NULL) return -1;
hdr->wrbufsize = sf * 3;
}
for(i=0; i<sf; i++)
{
value = (buf[i + buf_offset] / bitvalue) - phys_offset;
if(value>digmax) value = digmax;
if(value<digmin) value = digmin;
hdr->wrbuf[i * 3] = value & 0xff;
hdr->wrbuf[i * 3 + 1] = (value >> 8) & 0xff;
hdr->wrbuf[i * 3 + 2] = (value >> 16) & 0xff;
}
if(fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) return -1;
}
buf_offset += sf;
}
if(edflib_write_tal(hdr, file)) return -1;
hdr->datarecords++;
fflush(file);
return 0;
}
static int edflib_write_edf_header(struct edfhdrblock *hdr)
{
int i, j, p, q,
len,
rest,
edfsignals;
char str[128];
struct tm *date_time;
time_t elapsed_time;
FILE *file;
file = hdr->file_hdl;
edfsignals = hdr->edfsignals;
if(edfsignals<0) return EDFLIB_NO_SIGNALS;
if(edfsignals>EDFLIB_MAXSIGNALS) return EDFLIB_TOO_MANY_SIGNALS;
hdr->eq_sf = 1;
hdr->recordsize = 0;
hdr->total_annot_bytes = EDFLIB_ANNOTATION_BYTES * hdr->nr_annot_chns;
for(i=0; i<edfsignals; i++)
{
if(hdr->edfparam[i].smp_per_record<1) return EDFLIB_NO_SAMPLES_IN_RECORD;
if(hdr->edfparam[i].dig_max==hdr->edfparam[i].dig_min) return EDFLIB_DIGMIN_IS_DIGMAX;
if(hdr->edfparam[i].dig_max<hdr->edfparam[i].dig_min) return EDFLIB_DIGMAX_LOWER_THAN_DIGMIN;
if(hdr->edfparam[i].phys_max==hdr->edfparam[i].phys_min) return EDFLIB_PHYSMIN_IS_PHYSMAX;
hdr->recordsize += hdr->edfparam[i].smp_per_record;
if(i > 0)
{
if(hdr->edfparam[i].smp_per_record != hdr->edfparam[i-1].smp_per_record)
{
hdr->eq_sf = 0;
}
}
}
if(hdr->edf)
{
hdr->recordsize *= 2;
hdr->recordsize += hdr->total_annot_bytes;
if(hdr->recordsize > (10 * 1024 * 1024)) /* datarecord size should not exceed 10MB for EDF */
{
return EDFLIB_DATARECORD_SIZE_TOO_BIG;
} /* if your application gets hit by this limitation, lower the value for the datarecord duration */
/* using the function edf_set_datarecord_duration() */
}
else
{
hdr->recordsize *= 3;
hdr->recordsize += hdr->total_annot_bytes;
if(hdr->recordsize > (15 * 1024 * 1024)) /* datarecord size should not exceed 15MB for BDF */
{
return EDFLIB_DATARECORD_SIZE_TOO_BIG;
} /* if your application gets hit by this limitation, lower the value for the datarecord duration */
/* using the function edf_set_datarecord_duration() */
}
for(i=0; i<edfsignals; i++)
{
hdr->edfparam[i].bitvalue = (hdr->edfparam[i].phys_max - hdr->edfparam[i].phys_min) / (hdr->edfparam[i].dig_max - hdr->edfparam[i].dig_min);
hdr->edfparam[i].offset = hdr->edfparam[i].phys_max / hdr->edfparam[i].bitvalue - hdr->edfparam[i].dig_max;
}
rewind(file);
if(hdr->edf)
{
fprintf(file, "0 ");
}
else
{
fputc(255, file);
fprintf(file, "BIOSEMI");
}
p = 0;
if(hdr->plus_birthdate[0]==0)
{
rest = 72;
}
else
{
rest = 62;
}
len = strlen(hdr->plus_patientcode);
if(len && rest)
{
if(len>rest)
{
len = rest;
rest = 0;
}
else
{
rest -= len;
}
edflib_strlcpy(str, hdr->plus_patientcode, 128);
edflib_latin1_to_ascii(str, len);
str[len] = 0;
for(i=0; i<len; i++)
{
if(str[i]==' ')
{
str[i] = '_';
}
}
p += fprintf(file, "%s ", str);
}
else
{
p += fprintf(file, "X ");
}
if(hdr->plus_gender[0]=='M')
{
fputc('M', file);
}
else
{
if(hdr->plus_gender[0]=='F')
{
fputc('F', file);
}
else
{
fputc('X', file);
}
}
fputc(' ', file);
p +=2;
if(hdr->plus_birthdate[0]==0)
{
fputc('X', file);
fputc(' ', file);
p +=2;
}
else
{
fputc(hdr->plus_birthdate[0], file);
fputc(hdr->plus_birthdate[1], file);
fputc('-', file);
q = edflib_atoi_nonlocalized(&(hdr->plus_birthdate[3]));
switch(q)
{
case 1: fprintf(file, "JAN"); break;
case 2: fprintf(file, "FEB"); break;
case 3: fprintf(file, "MAR"); break;
case 4: fprintf(file, "APR"); break;
case 5: fprintf(file, "MAY"); break;
case 6: fprintf(file, "JUN"); break;
case 7: fprintf(file, "JUL"); break;
case 8: fprintf(file, "AUG"); break;
case 9: fprintf(file, "SEP"); break;
case 10: fprintf(file, "OCT"); break;
case 11: fprintf(file, "NOV"); break;
case 12: fprintf(file, "DEC"); break;
}
fputc('-', file);
fputc(hdr->plus_birthdate[6], file);
fputc(hdr->plus_birthdate[7], file);
fputc(hdr->plus_birthdate[8], file);
fputc(hdr->plus_birthdate[9], file);
fputc(' ', file);
p += 12;
}
len = strlen(hdr->plus_patient_name);
if(len && rest)
{
if(len>rest)
{
len = rest;
rest = 0;
}
else
{
rest -= len;
}
edflib_strlcpy(str, hdr->plus_patient_name, 128);
edflib_latin1_to_ascii(str, len);
str[len] = 0;
for(i=0; i<len; i++)
{
if(str[i]==' ')
{
str[i] = '_';
}
}
p += fprintf(file, "%s", str);
}
else
{
fputc('X', file);
p++;
}
if(rest)
{
fputc(' ', file);
p++;
rest--;
}
len = strlen(hdr->plus_patient_additional);
if(len && rest)
{
if(len>rest)
{
len = rest;
}
edflib_strlcpy(str, hdr->plus_patient_additional, 128);
edflib_latin1_to_ascii(str, len);
str[len] = 0;
p += fprintf(file, "%s", str);
}
for(; p<80; p++)
{
fputc(' ', file);
}
if(!hdr->startdate_year)
{
elapsed_time = time(NULL);
date_time = localtime(&elapsed_time);
hdr->startdate_year = date_time->tm_year + 1900;
hdr->startdate_month = date_time->tm_mon + 1;
hdr->startdate_day = date_time->tm_mday;
hdr->starttime_hour = date_time->tm_hour;
hdr->starttime_minute = date_time->tm_min;
hdr->starttime_second = date_time->tm_sec % 60;
}
p = 0;
p += fprintf(file, "Startdate %02u-", hdr->startdate_day);
switch(hdr->startdate_month)
{
case 1 : fprintf(file, "JAN"); break;
case 2 : fprintf(file, "FEB"); break;
case 3 : fprintf(file, "MAR"); break;
case 4 : fprintf(file, "APR"); break;
case 5 : fprintf(file, "MAY"); break;
case 6 : fprintf(file, "JUN"); break;
case 7 : fprintf(file, "JUL"); break;
case 8 : fprintf(file, "AUG"); break;
case 9 : fprintf(file, "SEP"); break;
case 10 : fprintf(file, "OCT"); break;
case 11 : fprintf(file, "NOV"); break;
case 12 : fprintf(file, "DEC"); break;
}
p += 3;
fputc('-', file);
p++;
p += edflib_fprint_int_number_nonlocalized(file, hdr->startdate_year, 4, 0);
fputc(' ', file);
p++;
rest = 42;
len = strlen(hdr->plus_admincode);
if(len && rest)
{
if(len>rest)
{
len = rest;
rest = 0;
}
else
{
rest -= len;
}
edflib_strlcpy(str, hdr->plus_admincode, 128);
edflib_latin1_to_ascii(str, len);
str[len] = 0;
for(i=0; i<len; i++)
{
if(str[i]==' ')
{
str[i] = '_';
}
}
p += fprintf(file, "%s", str);
}
else
{
p += fprintf(file, "X");
}
if(rest)
{
fputc(' ', file);
p++;
rest--;
}
len = strlen(hdr->plus_technician);
if(len && rest)
{
if(len>rest)
{
len = rest;
rest = 0;
}
else
{
rest -= len;
}
edflib_strlcpy(str, hdr->plus_technician, 128);
edflib_latin1_to_ascii(str, len);
str[len] = 0;
for(i=0; i<len; i++)
{
if(str[i]==' ')
{
str[i] = '_';
}
}
p += fprintf(file, "%s", str);
}
else
{
p += fprintf(file, "X");
}
if(rest)
{
fputc(' ', file);
p++;
rest--;
}
len = strlen(hdr->plus_equipment);
if(len && rest)
{
if(len>rest)
{
len = rest;
rest = 0;
}
else
{
rest -= len;
}
edflib_strlcpy(str, hdr->plus_equipment, 128);
edflib_latin1_to_ascii(str, len);
str[len] = 0;
for(i=0; i<len; i++)
{
if(str[i]==' ')
{
str[i] = '_';
}
}
p += fprintf(file, "%s", str);
}
else
{
p += fprintf(file, "X");
}
if(rest)
{
fputc(' ', file);
p++;
rest--;
}
len = strlen(hdr->plus_recording_additional);
if(len && rest)
{
if(len>rest)
{
len = rest;
}
edflib_strlcpy(str, hdr->plus_recording_additional, 128);
edflib_latin1_to_ascii(str, len);
str[len] = 0;
p += fprintf(file, "%s", str);
}
for(; p<80; p++)
{
fputc(' ', file);
}
fprintf(file, "%02u.%02u.%02u", hdr->startdate_day, hdr->startdate_month, (hdr->startdate_year % 100));
fprintf(file, "%02u.%02u.%02u", hdr->starttime_hour, hdr->starttime_minute, hdr->starttime_second);
p = edflib_fprint_int_number_nonlocalized(file, (edfsignals + hdr->nr_annot_chns + 1) * 256, 0, 0);
for(; p<8; p++)
{
fputc(' ', file);
}
if(hdr->edf)
{
fprintf(file, "EDF+C");
}
else
{
fprintf(file, "BDF+C");
}
for(i=0; i<39; i++)
{
fputc(' ', file);
}
fprintf(file, "-1 ");
if(hdr->long_data_record_duration == EDFLIB_TIME_DIMENSION)
{
fprintf(file, "1 ");
}
else
{
edflib_snprint_number_nonlocalized(str, hdr->data_record_duration, 128);
edflib_strlcat(str, " ", 128);
str[8] = 0;
fprintf(file, "%s", str);
}
p = edflib_fprint_int_number_nonlocalized(file, edfsignals + hdr->nr_annot_chns, 0, 0);
for(; p<4; p++)
{
fputc(' ', file);
}
for(i=0; i<edfsignals; i++)
{
len = strlen(hdr->edfparam[i].label);
edflib_latin1_to_ascii(hdr->edfparam[i].label, len);
for(j=0; j<len; j++)
{
fputc(hdr->edfparam[i].label[j], file);
}
for(; j<16; j++)
{
fputc(' ', file);
}
}
for(j=0; j<hdr->nr_annot_chns; j++)
{
if(hdr->edf)
{
fprintf(file, "EDF Annotations ");
}
else
{
fprintf(file, "BDF Annotations ");
}
}
for(i=0; i<edfsignals; i++)
{
len = strlen(hdr->edfparam[i].transducer);
edflib_latin1_to_ascii(hdr->edfparam[i].transducer, len);
for(j=0; j<len; j++)
{
fputc(hdr->edfparam[i].transducer[j], file);
}
for(; j<80; j++)
{
fputc(' ', file);
}
}
for(j=0; j<hdr->nr_annot_chns; j++)
{
for(i=0; i<80; i++)
{
fputc(' ', file);
}
}
for(i=0; i<edfsignals; i++)
{
len = strlen(hdr->edfparam[i].physdimension);
edflib_latin1_to_ascii(hdr->edfparam[i].physdimension, len);
for(j=0; j<len; j++)
{
fputc(hdr->edfparam[i].physdimension[j], file);
}
for(; j<8; j++)
{
fputc(' ', file);
}
}
for(j=0; j<hdr->nr_annot_chns; j++)
{
fprintf(file, " ");
}
for(i=0; i<edfsignals; i++)
{
p = edflib_snprint_number_nonlocalized(str, hdr->edfparam[i].phys_min, 128);
for(; p<8; p++)
{
str[p] = ' ';
}
str[8] = 0;
fprintf(file, "%s", str);
}
for(j=0; j<hdr->nr_annot_chns; j++)
{
fprintf(file, "-1 ");
}
for(i=0; i<edfsignals; i++)
{
p = edflib_snprint_number_nonlocalized(str, hdr->edfparam[i].phys_max, 128);
for(; p<8; p++)
{
str[p] = ' ';
}
str[8] = 0;
fprintf(file, "%s", str);
}
for(j=0; j<hdr->nr_annot_chns; j++)
{
fprintf(file, "1 ");
}
for(i=0; i<edfsignals; i++)
{
p = edflib_fprint_int_number_nonlocalized(file, hdr->edfparam[i].dig_min, 0, 0);
for(; p<8; p++)
{
fputc(' ', file);
}
}
for(j=0; j<hdr->nr_annot_chns; j++)
{
if(hdr->edf)
{
fprintf(file, "-32768 ");
}
else
{
fprintf(file, "-8388608");
}
}
for(i=0; i<edfsignals; i++)
{
p = edflib_fprint_int_number_nonlocalized(file, hdr->edfparam[i].dig_max, 0, 0);
for(; p<8; p++)
{
fputc(' ', file);
}
}
for(j=0; j<hdr->nr_annot_chns; j++)
{
if(hdr->edf)
{
fprintf(file, "32767 ");
}
else
{
fprintf(file, "8388607 ");
}
}
for(i=0; i<edfsignals; i++)
{
len = strlen(hdr->edfparam[i].prefilter);
edflib_latin1_to_ascii(hdr->edfparam[i].prefilter, len);
for(j=0; j<len; j++)
{
fputc(hdr->edfparam[i].prefilter[j], file);
}
for(; j<80; j++)
{
fputc(' ', file);
}
}
for(i=0; i<hdr->nr_annot_chns; i++)
{
for(j=0; j<80; j++)
{
fputc(' ', file);
}
}
for(i=0; i<edfsignals; i++)
{
p = edflib_fprint_int_number_nonlocalized(file, hdr->edfparam[i].smp_per_record, 0, 0);
for(; p<8; p++)
{
fputc(' ', file);
}
}
for(j=0; j<hdr->nr_annot_chns; j++)
{
if(hdr->edf)
{
p = edflib_fprint_int_number_nonlocalized(file, EDFLIB_ANNOTATION_BYTES / 2, 0, 0);
for(; p<8; p++)
{
fputc(' ', file);
}
}
else
{
p = edflib_fprint_int_number_nonlocalized(file, EDFLIB_ANNOTATION_BYTES / 3, 0, 0);
for(; p<8; p++)
{
fputc(' ', file);
}
}
}
for(i=0; i<(edfsignals * 32); i++)
{
fputc(' ', file);
}
for(i=0; i<(hdr->nr_annot_chns * 32); i++)
{
fputc(' ', file);
}
return 0;
}
int edf_set_label(int handle, int edfsignal, const char *label)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
if((edfsignal<0) || (edfsignal>=hdrlist[handle]->edfsignals)) return -1;
strncpy(hdrlist[handle]->edfparam[edfsignal].label, label, 16);
hdrlist[handle]->edfparam[edfsignal].label[16] = 0;
edflib_remove_padding_trailing_spaces(hdrlist[handle]->edfparam[edfsignal].label);
return 0;
}
int edf_set_physical_dimension(int handle, int edfsignal, const char *phys_dim)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
if((edfsignal<0) || (edfsignal>=hdrlist[handle]->edfsignals)) return -1;
strncpy(hdrlist[handle]->edfparam[edfsignal].physdimension, phys_dim, 8);
hdrlist[handle]->edfparam[edfsignal].physdimension[8] = 0;
edflib_remove_padding_trailing_spaces(hdrlist[handle]->edfparam[edfsignal].physdimension);
return 0;
}
int edf_set_physical_maximum(int handle, int edfsignal, double phys_max)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
if((edfsignal<0) || (edfsignal>=hdrlist[handle]->edfsignals)) return -1;
hdrlist[handle]->edfparam[edfsignal].phys_max = phys_max;
return 0;
}
int edf_set_physical_minimum(int handle, int edfsignal, double phys_min)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
if((edfsignal<0) || (edfsignal>=hdrlist[handle]->edfsignals)) return -1;
hdrlist[handle]->edfparam[edfsignal].phys_min = phys_min;
return 0;
}
int edf_set_digital_maximum(int handle, int edfsignal, int dig_max)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
if((edfsignal<0) || (edfsignal>=hdrlist[handle]->edfsignals)) return -1;
if(hdrlist[handle]->edf)
{
if(dig_max > 0x7fff) return -1;
}
else
{
if(dig_max > 0x7fffff) return -1;
}
hdrlist[handle]->edfparam[edfsignal].dig_max = dig_max;
return 0;
}
int edf_set_digital_minimum(int handle, int edfsignal, int dig_min)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
if((edfsignal<0) || (edfsignal>=hdrlist[handle]->edfsignals)) return -1;
if(hdrlist[handle]->edf)
{
if(dig_min < (-0x8000)) return -1;
}
else
{
if(dig_min < (-0x800000)) return -1;
}
hdrlist[handle]->edfparam[edfsignal].dig_min = dig_min;
return 0;
}
int edf_set_patientname(int handle, const char *patientname)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
strncpy(hdrlist[handle]->plus_patient_name, patientname, 80);
hdrlist[handle]->plus_patient_name[80] = 0;
edflib_remove_padding_trailing_spaces(hdrlist[handle]->plus_patient_name);
return 0;
}
int edf_set_patientcode(int handle, const char *patientcode)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
strncpy(hdrlist[handle]->plus_patientcode, patientcode, 80);
hdrlist[handle]->plus_patientcode[80] = 0;
edflib_remove_padding_trailing_spaces(hdrlist[handle]->plus_patientcode);
return 0;
}
int edf_set_gender(int handle, int gender)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
if((gender<0)||(gender>1)) return -1;
if(gender)
{
hdrlist[handle]->plus_gender[0] = 'M';
}
else
{
hdrlist[handle]->plus_gender[0] = 'F';
}
hdrlist[handle]->plus_gender[1] = 0;
return 0;
}
int edf_set_birthdate(int handle, int birthdate_year, int birthdate_month, int birthdate_day)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
if((birthdate_year<1800) || (birthdate_year>3000) ||
(birthdate_month<1) || (birthdate_month>12) ||
(birthdate_day<1) || (birthdate_day>31))
{
return -1;
}
sprintf(hdrlist[handle]->plus_birthdate, "%02i.%02i.%02i%02i", birthdate_day, birthdate_month, birthdate_year / 100, birthdate_year % 100);
hdrlist[handle]->plus_birthdate[10] = 0;
return 0;
}
int edf_set_patient_additional(int handle, const char *patient_additional)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
strncpy(hdrlist[handle]->plus_patient_additional, patient_additional, 80);
hdrlist[handle]->plus_patient_additional[80] = 0;
edflib_remove_padding_trailing_spaces(hdrlist[handle]->plus_patient_additional);
return 0;
}
int edf_set_admincode(int handle, const char *admincode)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
strncpy(hdrlist[handle]->plus_admincode, admincode, 80);
hdrlist[handle]->plus_admincode[80] = 0;
edflib_remove_padding_trailing_spaces(hdrlist[handle]->plus_admincode);
return 0;
}
int edf_set_technician(int handle, const char *technician)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
strncpy(hdrlist[handle]->plus_technician, technician, 80);
hdrlist[handle]->plus_technician[80] = 0;
edflib_remove_padding_trailing_spaces(hdrlist[handle]->plus_technician);
return 0;
}
int edf_set_equipment(int handle, const char *equipment)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
strncpy(hdrlist[handle]->plus_equipment, equipment, 80);
hdrlist[handle]->plus_equipment[80] = 0;
edflib_remove_padding_trailing_spaces(hdrlist[handle]->plus_equipment);
return 0;
}
int edf_set_recording_additional(int handle, const char *recording_additional)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
strncpy(hdrlist[handle]->plus_recording_additional, recording_additional, 80);
hdrlist[handle]->plus_recording_additional[80] = 0;
edflib_remove_padding_trailing_spaces(hdrlist[handle]->plus_recording_additional);
return 0;
}
int edf_set_startdatetime(int handle, int startdate_year, int startdate_month, int startdate_day,
int starttime_hour, int starttime_minute, int starttime_second)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
if((startdate_year<1985) || (startdate_year>2084) ||
(startdate_month<1) || (startdate_month>12) ||
(startdate_day<1) || (startdate_day>31) ||
(starttime_hour<0) || (starttime_hour>23) ||
(starttime_minute<0) || (starttime_minute>59) ||
(starttime_second<0) || (starttime_second>59))
{
return -1;
}
hdrlist[handle]->startdate_year = startdate_year;
hdrlist[handle]->startdate_month = startdate_month;
hdrlist[handle]->startdate_day = startdate_day;
hdrlist[handle]->starttime_hour = starttime_hour;
hdrlist[handle]->starttime_minute = starttime_minute;
hdrlist[handle]->starttime_second = starttime_second;
return 0;
}
int edfwrite_annotation_utf8(int handle, long long onset, long long duration, const char *description)
{
int i;
struct edf_write_annotationblock *list_annot, *malloc_list;
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(onset<0LL) return -1;
if(hdrlist[handle]->annots_in_file >= hdrlist[handle]->annotlist_sz)
{
malloc_list = (struct edf_write_annotationblock *)realloc(write_annotationslist[handle],
sizeof(struct edf_write_annotationblock) * (hdrlist[handle]->annotlist_sz + EDFLIB_ANNOT_MEMBLOCKSZ));
if(malloc_list==NULL)
{
return -1;
}
write_annotationslist[handle] = malloc_list;
hdrlist[handle]->annotlist_sz += EDFLIB_ANNOT_MEMBLOCKSZ;
}
list_annot = write_annotationslist[handle] + hdrlist[handle]->annots_in_file;
list_annot->onset = onset;
list_annot->duration = duration;
strncpy(list_annot->annotation, description, EDFLIB_WRITE_MAX_ANNOTATION_LEN);
list_annot->annotation[EDFLIB_WRITE_MAX_ANNOTATION_LEN] = 0;
for(i=0; ; i++)
{
if(list_annot->annotation[i] == 0)
{
break;
}
if(((unsigned char *)(list_annot->annotation))[i] < 32)
{
list_annot->annotation[i] = '.';
}
}
hdrlist[handle]->annots_in_file++;
return 0;
}
int edfwrite_annotation_latin1(int handle, long long onset, long long duration, const char *description)
{
struct edf_write_annotationblock *list_annot, *malloc_list;
char str[EDFLIB_WRITE_MAX_ANNOTATION_LEN + 1];
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(onset<0LL) return -1;
if(hdrlist[handle]->annots_in_file >= hdrlist[handle]->annotlist_sz)
{
malloc_list = (struct edf_write_annotationblock *)realloc(write_annotationslist[handle],
sizeof(struct edf_write_annotationblock) * (hdrlist[handle]->annotlist_sz + EDFLIB_ANNOT_MEMBLOCKSZ));
if(malloc_list==NULL)
{
return -1;
}
write_annotationslist[handle] = malloc_list;
hdrlist[handle]->annotlist_sz += EDFLIB_ANNOT_MEMBLOCKSZ;
}
list_annot = write_annotationslist[handle] + hdrlist[handle]->annots_in_file;
list_annot->onset = onset;
list_annot->duration = duration;
strncpy(str, description, EDFLIB_WRITE_MAX_ANNOTATION_LEN);
str[EDFLIB_WRITE_MAX_ANNOTATION_LEN] = 0;
edflib_latin12utf8(str, strlen(str));
strncpy(list_annot->annotation, str, EDFLIB_WRITE_MAX_ANNOTATION_LEN);
list_annot->annotation[EDFLIB_WRITE_MAX_ANNOTATION_LEN] = 0;
hdrlist[handle]->annots_in_file++;
return 0;
}
static void edflib_remove_padding_trailing_spaces(char *str)
{
int i;
while(str[0]==' ')
{
for(i=0; ; i++)
{
if(str[i]==0)
{
break;
}
str[i] = str[i+1];
}
}
for(i = strlen(str); i>0; i--)
{
if(str[i-1]==' ')
{
str[i-1] = 0;
}
else
{
break;
}
}
}
int edf_set_prefilter(int handle, int edfsignal, const char *prefilter)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
if((edfsignal<0) || (edfsignal>=hdrlist[handle]->edfsignals)) return -1;
if(hdrlist[handle]->datarecords) return -1;
strncpy(hdrlist[handle]->edfparam[edfsignal].prefilter, prefilter, 80);
hdrlist[handle]->edfparam[edfsignal].prefilter[80] = 0;
edflib_remove_padding_trailing_spaces(hdrlist[handle]->edfparam[edfsignal].prefilter);
return 0;
}
int edf_set_transducer(int handle, int edfsignal, const char *transducer)
{
if((handle<0)||(handle>=EDFLIB_MAXFILES)) return -1;
if(hdrlist[handle]==NULL) return -1;
if(!hdrlist[handle]->writemode) return -1;
if(hdrlist[handle]->datarecords) return -1;
if((edfsignal<0) || (edfsignal>=hdrlist[handle]->edfsignals)) return -1;
if(hdrlist[handle]->datarecords) return -1;
strncpy(hdrlist[handle]->edfparam[edfsignal].transducer, transducer, 80);
hdrlist[handle]->edfparam[edfsignal].transducer[80] = 0;
edflib_remove_padding_trailing_spaces(hdrlist[handle]->edfparam[edfsignal].transducer);
return 0;
}
/* minimum is the minimum digits that will be printed (minus sign not included), leading zero's will be added if necessary */
/* if sign is zero, only negative numbers will have the sign '-' character */
/* if sign is one, the sign '+' or '-' character will always be printed */
/* returns the amount of characters printed */
static int edflib_fprint_int_number_nonlocalized(FILE *file, int q, int minimum, int sign)
{
int flag=0, z, i, j=0, base = 1000000000;
if(minimum < 0)
{
minimum = 0;
}
if(minimum > 9)
{
flag = 1;
}
if(q < 0)
{
fputc('-', file);
j++;
base = -base;
}
else
{
if(sign)
{
fputc('+', file);
j++;
}
}
for(i=10; i; i--)
{
if(minimum == i)
{
flag = 1;
}
z = q / base;
q %= base;
if(z || flag)
{
fputc('0' + z, file);
j++;
flag = 1;
}
base /= 10;
}
if(!flag)
{
fputc('0', file);
j++;
}
return j;
}
/* minimum is the minimum digits that will be printed (minus sign not included), leading zero's will be added if necessary */
/* if sign is zero, only negative numbers will have the sign '-' character */
/* if sign is one, the sign '+' or '-' character will always be printed */
/* returns the amount of characters printed */
static int edflib_fprint_ll_number_nonlocalized(FILE *file, long long q, int minimum, int sign)
{
int flag=0, z, i, j=0;
long long base = 1000000000000000000LL;
if(minimum < 0)
{
minimum = 0;
}
if(minimum > 18)
{
flag = 1;
}
if(q < 0LL)
{
fputc('-', file);
j++;
base = -base;
}
else
{
if(sign)
{
fputc('+', file);
j++;
}
}
for(i=19; i; i--)
{
if(minimum == i)
{
flag = 1;
}
z = q / base;
q %= base;
if(z || flag)
{
fputc('0' + z, file);
j++;
flag = 1;
}
base /= 10LL;
}
if(!flag)
{
fputc('0', file);
j++;
}
return j;
}
/* minimum is the minimum digits that will be printed (minus sign not included), leading zero's will be added if necessary */
/* if sign is zero, only negative numbers will have the sign '-' character */
/* if sign is one, the sign '+' or '-' character will always be printed */
/* returns the amount of characters printed */
/*
static int edflib_sprint_int_number_nonlocalized(char *str, int q, int minimum, int sign)
{
int flag=0, z, i, j=0, base = 1000000000;
if(minimum < 0)
{
minimum = 0;
}
if(minimum > 9)
{
flag = 1;
}
if(q < 0)
{
str[j++] = '-';
q = -q;
}
else
{
if(sign)
{
str[j++] = '+';
}
}
for(i=10; i; i--)
{
if(minimum == i)
{
flag = 1;
}
z = q / base;
q %= base;
if(z || flag)
{
str[j++] = '0' + z;
flag = 1;
}
base /= 10;
}
if(!flag)
{
str[j++] = '0';
}
str[j] = 0;
return j;
}
*/
/* minimum is the minimum digits that will be printed (minus sign not included), leading zero's will be added if necessary */
/* if sign is zero, only negative numbers will have the sign '-' character */
/* if sign is one, the sign '+' or '-' character will always be printed */
/* returns the amount of characters printed */
static int edflib_snprint_ll_number_nonlocalized(char *dest, long long q, int minimum, int sign, int sz)
{
int flag=0, z, i, j=0;
long long base = 1000000000000000000LL;
if(sz < 1)
{
return 0;
}
if(minimum < 0)
{
minimum = 0;
}
if(minimum > 18)
{
flag = 1;
}
if(q < 0LL)
{
dest[j++] = '-';
base = -base;
}
else
{
if(sign)
{
dest[j++] = '+';
}
}
if(j == sz)
{
dest[--j] = 0;
return j;
}
for(i=19; i; i--)
{
if(minimum == i)
{
flag = 1;
}
z = q / base;
q %= base;
if(z || flag)
{
dest[j++] = '0' + z;
if(j == sz)
{
dest[--j] = 0;
return j;
}
flag = 1;
}
base /= 10LL;
}
if(!flag)
{
dest[j++] = '0';
}
if(j == sz)
{
dest[--j] = 0;
return j;
}
dest[j] = 0;
return j;
}
static int edflib_snprint_number_nonlocalized(char *dest, double val, int sz)
{
int flag=0, z, i, j=0, q, base = 1000000000;
double var;
if(sz < 1) return 0;
q = (int)val;
var = val - q;
if(val < 0.0)
{
dest[j++] = '-';
if(q < 0)
{
base = -base;
}
}
if(j == sz)
{
dest[--j] = 0;
return j;
}
for(i=10; i; i--)
{
z = q / base;
q %= base;
if(z || flag)
{
dest[j++] = '0' + z;
if(j == sz)
{
dest[--j] = 0;
return j;
}
flag = 1;
}
base /= 10;
}
if(!flag)
{
dest[j++] = '0';
}
if(j == sz)
{
dest[--j] = 0;
return j;
}
base = 100000000;
var *= (base * 10);
q = (int)var;
if(q < 0)
{
base = -base;
}
if(!q)
{
dest[j] = 0;
return j;
}
dest[j++] = '.';
if(j == sz)
{
dest[--j] = 0;
return j;
}
for(i=9; i; i--)
{
z = q / base;
q %= base;
dest[j++] = '0' + z;
if(j == sz)
{
dest[--j] = 0;
return j;
}
base /= 10;
}
dest[j] = 0;
j--;
for(; j>0; j--)
{
if(dest[j] == '0')
{
dest[j] = 0;
}
else
{
j++;
break;
}
}
return j;
}
static double edflib_atof_nonlocalized(const char *str)
{
int i=0, j, dot_pos=-1, decimals=0, sign=1, exp_pos=-1, exp_sign=1, exp_val=0;
double value, value2=0.0;
value = edflib_atoi_nonlocalized(str);
while(str[i] == ' ')
{
i++;
}
if((str[i] == '+') || (str[i] == '-'))
{
if(str[i] == '-')
{
sign = -1;
}
i++;
}
for(; ; i++)
{
if(str[i] == 0)
{
break;
}
if((str[i] == 'e') || (str[i] == 'E'))
{
exp_pos = i;
break;
}
if(((str[i] < '0') || (str[i] > '9')) && (str[i] != '.'))
{
break;
}
if(dot_pos >= 0)
{
if((str[i] >= '0') && (str[i] <= '9'))
{
decimals++;
}
else
{
break;
}
}
if(str[i] == '.')
{
if(dot_pos < 0)
{
dot_pos = i;
}
}
}
if(decimals)
{
value2 = edflib_atoi_nonlocalized(str + dot_pos + 1) * sign;
i = 1;
while(decimals--)
{
i *= 10;
}
value2 /= i;
value += value2;
}
if(exp_pos > 0)
{
i = exp_pos + 1;
if(str[i])
{
if(str[i] == '+')
{
i++;
}
else if(str[i] == '-')
{
exp_sign = -1;
i++;
}
if(str[i])
{
exp_val = edflib_atoi_nonlocalized(str + i);
if(exp_val > 0)
{
for(j=0; j<exp_val; j++)
{
if(exp_sign > 0)
{
value *= 10;
}
else
{
value /= 10;
}
}
}
}
}
}
return value;
}
static int edflib_atoi_nonlocalized(const char *str)
{
int i=0, value=0, sign=1;
while(str[i] == ' ')
{
i++;
}
if((str[i] == '+') || (str[i] == '-'))
{
if(str[i] == '-')
{
sign = -1;
}
i++;
}
for( ; ; i++)
{
if(str[i] == 0)
{
break;
}
if((str[i] < '0') || (str[i] > '9'))
{
break;
}
value *= 10;
value += ((str[i] - '0') * sign);
}
return value;
}
static int edflib_write_tal(struct edfhdrblock *hdr, FILE *file)
{
int p;
char str[EDFLIB_ANNOTATION_BYTES * (EDFLIB_MAX_ANNOTATION_CHANNELS + 1)];
p = edflib_snprint_ll_number_nonlocalized(str, (hdr->datarecords * hdr->long_data_record_duration + hdr->starttime_offset) / EDFLIB_TIME_DIMENSION, 0, 1, EDFLIB_ANNOTATION_BYTES * (EDFLIB_MAX_ANNOTATION_CHANNELS + 1));
if((hdr->long_data_record_duration % EDFLIB_TIME_DIMENSION) || (hdr->starttime_offset))
{
str[p++] = '.';
p += edflib_snprint_ll_number_nonlocalized(str + p, (hdr->datarecords * hdr->long_data_record_duration + hdr->starttime_offset) % EDFLIB_TIME_DIMENSION, 7, 0, (EDFLIB_ANNOTATION_BYTES * (EDFLIB_MAX_ANNOTATION_CHANNELS + 1)) - p);
}
str[p++] = 20;
str[p++] = 20;
for(; p<hdr->total_annot_bytes; p++)
{
str[p] = 0;
}
if(fwrite(str, hdr->total_annot_bytes, 1, file) != 1)
{
return -1;
}
return 0;
}
static int edflib_strlcpy(char *dst, const char *src, int sz)
{
int srclen;
sz--;
srclen = strlen(src);
if(srclen > sz) srclen = sz;
memcpy(dst, src, srclen);
dst[srclen] = 0;
return srclen;
}
static int edflib_strlcat(char *dst, const char *src, int sz)
{
int srclen,
dstlen;
dstlen = strlen(dst);
sz -= dstlen + 1;
if(!sz) return dstlen;
srclen = strlen(src);
if(srclen > sz) srclen = sz;
memcpy(dst + dstlen, src, srclen);
dst[dstlen + srclen] = 0;
return (dstlen + srclen);
}