1 /*
2 sopen_axg_read is a helper function to sopen, reading AXG data.
3
4 Copyright (C) 2008-2014 Alois Schloegl <alois.schloegl@gmail.com>
5 This file is part of the "BioSig for C/C++" repository
6 (biosig4c++) at http://biosig.sf.net/
7
8 BioSig is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 3
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #define _GNU_SOURCE
23
24 #include <assert.h>
25 #include <ctype.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/stat.h>
29 #include <iconv.h>
30
31 #if !defined(__APPLE__) && defined (_LIBICONV_H)
32 #define iconv libiconv
33 #define iconv_open libiconv_open
34 #define iconv_close libiconv_close
35 #endif
36
37
38 #include "../biosig-dev.h"
39
40 #define min(a,b) (((a) < (b)) ? (a) : (b))
41 #define max(a,b) (((a) > (b)) ? (a) : (b))
42
sopen_axg_read(HDRTYPE * hdr)43 void sopen_axg_read(HDRTYPE* hdr) {
44
45 hdr->FILE.LittleEndian = 0;
46
47 // read whole file into RAM
48 size_t count = hdr->HeadLen;
49 while (!ifeof(hdr)) {
50 const int minsize = 1024;
51 hdr->AS.Header = (uint8_t*)realloc(hdr->AS.Header, 2*count+minsize);
52 count += ifread(hdr->AS.Header+count, 1, count+minsize, hdr);
53 }
54 ifclose(hdr);
55
56 if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %i) %p %i\n", __FILE__, __LINE__, hdr->CHANNEL, hdr->NS );
57
58 int32_t nCol;
59 switch ((int) hdr->VERSION) {
60 case 1:
61 case 2:
62 nCol = bei16p(hdr->AS.Header+6);
63 hdr->HeadLen = 8;
64 break;
65 case 3:
66 case 4:
67 case 5:
68 case 6:
69 nCol = bei32p(hdr->AS.Header+8);
70 hdr->HeadLen = 12;
71 break;
72 default:
73 biosigERROR(hdr,B4C_FORMAT_UNSUPPORTED,"AXG - unsupported version number");
74 return;
75 }
76
77 /* hack: for now each trace (i.e. column) becomes a separate channel -
78 later the traces of the channels will be reorganized
79 */
80 CHANNEL_TYPE *TEMPCHANNEL = (CHANNEL_TYPE*)malloc(nCol*sizeof(CHANNEL_TYPE));
81 char **ValLabel = (char**)malloc(nCol*sizeof(char*));
82 uint32_t *keyLabel = (uint32_t*)malloc(nCol*sizeof(uint32_t));
83
84 if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %i) %p %i\n", __FILE__, __LINE__, hdr->CHANNEL, hdr->NS );
85
86 /******* read all column/traces ******/
87 int32_t k;
88 uint8_t *pos = hdr->AS.Header+hdr->HeadLen;
89 hdr->SPR = beu32p(pos);
90 switch ((int) hdr->VERSION) {
91 case 1:
92 for (k = 0; k < nCol; k++) {
93 CHANNEL_TYPE *hc = TEMPCHANNEL+k;
94 hc->GDFTYP = 16; //float
95 hc->PhysDimCode = 0;
96 hc->SPR = beu32p(pos);
97
98 int strlen = pos[4]; // string in Pascal format
99 if (strlen > 79) {
100 biosigERROR(hdr,B4C_FORMAT_UNSUPPORTED,"AXG - invalid title length ");
101 return;
102 }
103
104 /* Organize channels */
105 uint32_t i;
106 for (i = 0; i < hdr->NS; i++) {
107 // check if channel with same title already exists
108 if (!memcmp(ValLabel[hdr->NS], pos+4, strlen)) {
109 keyLabel[k] = hdr->NS;
110 break;
111 }
112 }
113 if (i==hdr->NS) {
114 // in case of new title, add another channel
115 ValLabel[hdr->NS] = (char*)pos+4;
116 keyLabel[k] = hdr->NS;
117 hdr->NS++;
118 }
119
120 // start of data section
121 hc->bufptr = pos+84;
122 pos += 84 + hc->SPR * sizeof(float);
123
124 }
125 break;
126 case 2:
127 for (k = 0; k < nCol; k++) {
128 CHANNEL_TYPE *hc = TEMPCHANNEL+k;
129 hc->GDFTYP = 3; // int16
130 hc->PhysDimCode = 0;
131 hc->SPR = beu32p(pos);
132 if (k==0) {
133 hc->Off = bef32p(pos+84);
134 hc->Cal = bef32p(pos+88);
135 hc->bufptr = NULL;
136 hdr->SampleRate = 1.0 / hc->Cal;
137 }
138 else {
139 hc->Cal = bef32p(pos+84);
140 hc->Off = 0.0;
141 hc->bufptr = pos + 88;
142 }
143 int strlen = pos[4]; // string in Pascal format
144 if (strlen > 79) {
145 biosigERROR(hdr,B4C_FORMAT_UNSUPPORTED,"AXG - invalid title length ");
146 return;
147 }
148
149 biosigERROR(hdr,B4C_FORMAT_UNSUPPORTED,"AXG - version 2 not supported yet ");
150 return;
151
152 // start of data sectioB
153 pos += (k==0 ? 92 : 88 + hc->SPR * sizeof(int16_t) );
154
155 }
156 break;
157 case 6:
158 for (k=0; k < nCol; k++) {
159
160 if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %i) %p %i\n", __FILE__, __LINE__, hdr->CHANNEL, k );
161
162 CHANNEL_TYPE *hc = TEMPCHANNEL+k;
163 hc->SPR = beu32p(pos);
164 uint32_t datatype = beu32p(pos+4);
165 size_t titleLen = beu32p(pos+8);
166 char *inbuf = (char*)pos + 12;
167 hc->bufptr = pos + 12 + titleLen;
168
169 if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %i) %i %i %i\n", __FILE__, __LINE__, (int)datatype, (int)titleLen, (int)hc->SPR);
170 /*
171 // The only types used for data file columns are...
172 // ShortArrayType = 4 IntArrayType = 5
173 // FloatArrayType = 6 DoubleArrayType = 7
174 // SeriesArrayType = 9 ScaledShortArrayType = 10
175 */
176 hc->Cal = 1.0;
177 hc->Off = 0.0;
178 hc->GDFTYP = datatype; //TEMPCHANNEL.GDFTYP uses a different encoding than standard GDFTYP
179 hc->OnOff = 1;
180 switch (datatype) {
181 case 4: // int16
182 hc->GDFTYP=3; break;
183 case 5: // int32
184 hc->GDFTYP=5; break;
185 case 6: // float32
186 hc->GDFTYP=16; break;
187 case 7: // double
188 hc->GDFTYP=17; break;
189 case 9: hc->GDFTYP = 17; // series
190 // double firstval = bef64p(hc->bufptr);
191 double increment = bef64p(hc->bufptr+8);
192 hc->bufptr = NULL;
193 hc->OnOff = 0;
194 if (!memcmp(inbuf,"\0T\0i\0m\0e\0 \0(\0s\0)\0",8)) {
195 hdr->SampleRate = 1.0/increment;
196 //hc->OnOff = 2; // time axis
197 }
198 else {
199 biosigERROR(hdr, B4C_FORMAT_UNSUPPORTED, "AXG: series data not being a Time axis is not supported. ");
200 return;
201 }
202 break;
203 case 10: // scaled short
204 hc->Cal = bef64p(hc->bufptr);
205 hc->Off = bef64p(hc->bufptr+8);
206 break;
207 default:
208 hc->OnOff = 0;
209 }
210
211 if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %i) %p %i\n", __FILE__, __LINE__, hdr->CHANNEL, k );
212 if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %i): %i %i %i %i\n", __FILE__, __LINE__, (int)hc->SPR, (int)datatype, (int)titleLen, (int)(pos-hdr->AS.Header) );
213
214 /* Organize channels
215 find number of channels and
216 setup data structure that assignes each column to a channel
217 ValLabel contains the different Labels - one for each channel
218 keyLabel contains the channel number for the corresponding column
219 */
220 uint32_t i;
221 for (i = 0; i < hdr->NS; i++) {
222 // check if channel with same title already exists
223 uint32_t prevTitleLen = beu32p((uint8_t*)(ValLabel[i])-4);
224 if ((titleLen == prevTitleLen) && !memcmp(ValLabel[i], pos+12, titleLen)) {
225 keyLabel[k] = i;
226 break;
227 }
228 }
229 if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %i) %p %i\n", __FILE__, __LINE__, hdr->CHANNEL, k );
230 if (i==hdr->NS) {
231 // in case of new title, add another channel
232 ValLabel[hdr->NS] = (char*)pos+12; // pointer to title of channel 'nLabel', length of title is stored in beu32p(pos+8)
233 keyLabel[k] = hdr->NS;
234 hdr->NS++;
235 }
236
237 if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %i) %p %i\n", __FILE__, __LINE__, hdr->CHANNEL, k );
238 // pointer to data sections
239 hc->bufptr = pos + 12 + titleLen;
240
241
242 // move pos to the starting position of the next column
243 pos += 12 + titleLen;
244 // position of next column
245 switch (datatype) {
246 case 4:
247 pos += hc->SPR * sizeof(int16_t);
248 break;
249 case 5: //int32
250 case 6: //float
251 pos += hc->SPR * 4;
252 break;
253 case 7:
254 pos += hc->SPR * sizeof(double);
255 break;
256 case 9:
257 pos += 2 * sizeof(double);
258 break;
259 case 10:
260 pos += 2 * sizeof(double) + hc->SPR * sizeof(int16_t);
261 break;
262 default:
263 biosigERROR(hdr,B4C_FORMAT_UNSUPPORTED,"error reading AXG: unsupported data type");
264 }
265 if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %i): %i %i %i %i\n", __FILE__, __LINE__, (int)hc->SPR, (int)datatype, (int)titleLen, (int)(pos-hdr->AS.Header) );
266
267 }
268 break;
269 default:
270 biosigERROR(hdr,B4C_FORMAT_UNSUPPORTED,"AXG version is not supported");
271 }
272
273 if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %i) %p %p %i %i\n", __FILE__, __LINE__, TEMPCHANNEL, hdr->CHANNEL, (int)hdr->NS , (int)sizeof(CHANNEL_TYPE));
274
275 /* convert columns/traces into channels */
276 hdr->CHANNEL = (CHANNEL_TYPE*)realloc(hdr->CHANNEL, hdr->NS * sizeof(CHANNEL_TYPE));
277 uint32_t ns;
278 for (ns=0; ns < hdr->NS; ns++) {
279 CHANNEL_TYPE *hc = hdr->CHANNEL + ns;
280 hc->SPR = 0;
281 hc->GDFTYP = 0;
282 hc->OnOff = 1;
283 }
284 size_t EventN = 0;
285 hdr->SPR = 0;
286
287 if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %i) NS=%i nCol=%i\n", __FILE__, __LINE__, hdr->NS, nCol );
288
289 int flag_traces_of_first_sweep_done=0;
290 for (k=0; k < nCol; k++) {
291 /*
292 copy essential parameters ´(GDFTYP, OnOff, Cal, Off) from TEMPCHANNEL
293 and keep track of the number of samples SPR for each channel
294 */
295
296 // define GDFTYP, Cal, Off
297 ns = keyLabel[k]; // channel number for current column
298 CHANNEL_TYPE *hc = hdr->CHANNEL + ns;
299
300 hc->SPR += TEMPCHANNEL[k].SPR;
301
302 switch (TEMPCHANNEL[k].GDFTYP) {
303 case 4: // int16
304 if (hc->GDFTYP < 3) hc->GDFTYP = 3;
305 break;
306 case 5: // int32
307 if (hc->GDFTYP < 5) hc->GDFTYP = 5;
308 break;
309 case 6: // float32
310 if (hc->GDFTYP < 16) hc->GDFTYP = 16;
311 break;
312 case 7: // double
313 if (hc->GDFTYP < 17) hc->GDFTYP = 17;
314 break;
315 case 10: hc->GDFTYP = 3; // scaled short
316 if (hc->GDFTYP < 16) hc->GDFTYP = 16;
317 break;
318 default:
319 hc->OnOff = 0;
320 }
321
322 if (!flag_traces_of_first_sweep_done) {
323 hc->Cal = TEMPCHANNEL[k].Cal;
324 hc->Off = TEMPCHANNEL[k].Off;
325 }
326 else {
327 if (hc->Cal != TEMPCHANNEL[k].Cal || hc->Off != TEMPCHANNEL[k].Off) {
328 // in case input is scaled short, output shoud be float
329 hc->GDFTYP = max(16, hc->GDFTYP);
330 }
331 }
332
333 if (hdr->SPR < hc->SPR) hdr->SPR = hc->SPR;
334
335 if (ns+1 == hdr->NS) {
336 flag_traces_of_first_sweep_done = 1;
337
338 // ... add segment break in event table.
339 if ( hdr->EVENT.N + 1 >= EventN ) {
340 EventN += max(EventN, 16);
341 hdr->EVENT.POS = (uint32_t*)realloc(hdr->EVENT.POS, EventN * sizeof(*hdr->EVENT.POS));
342 hdr->EVENT.TYP = (uint16_t*)realloc(hdr->EVENT.TYP, EventN * sizeof(*hdr->EVENT.TYP));
343 }
344 hdr->EVENT.TYP[hdr->EVENT.N] = 0x7ffe;
345 hdr->EVENT.POS[hdr->EVENT.N] = hdr->SPR;
346 hdr->EVENT.N++;
347 }
348 }
349 hdr->EVENT.N--; // ignore last separator event
350
351 hdr->NRec = hdr->SPR;
352 hdr->SPR = 1;
353 uint32_t bi8 = 0;
354 for (ns=0; ns < hdr->NS; ns++) {
355 CHANNEL_TYPE *hc = hdr->CHANNEL+ns;
356 hc->bi8 = bi8;
357 hc->bi = bi8/8;
358 if (hc->OnOff != 1)
359 hc->SPR = 0;
360 else
361 bi8 += GDFTYP_BITS[hc->GDFTYP];
362 }
363 hdr->AS.bpb = bi8/8;
364
365 for (ns=0; ns < hdr->NS; ns++) {
366 CHANNEL_TYPE *hc = hdr->CHANNEL+ns;
367
368 // define hdr->channel[.].Label, hdr->channel[.].PhysDim
369 if (hdr->Version <= 2) {
370 // PascalToCString(ValLabel[ns]); // shift by 1 byte and terminate 0 char
371 int strlen = min(ValLabel[ns][0],MAX_LENGTH_LABEL);
372 strncpy(hc->Label, (ValLabel[ns])+1, strlen);
373
374 char *u1 = strrchr(ValLabel[ns],'(');
375 char *u2 = strrchr(ValLabel[ns],')');
376 if (u1 != NULL && u2 != NULL && u1 < u2) {
377 *u1 = 0;
378 *u2 = 0;
379 hc->PhysDimCode = PhysDimCode(u1+1);
380 }
381 }
382 else if (hdr->Version <= 6) {
383 char *inbuf = ValLabel[ns];
384 size_t inlen = beu32p((uint8_t*)(ValLabel[ns])-4);
385 char *outbuf = hc->Label;
386 size_t outlen = MAX_LENGTH_LABEL+1;
387 #if defined(_ICONV_H) || defined (_LIBICONV_H)
388 iconv_t ICONV = iconv_open("UTF-8","UCS-2BE");
389 size_t reticonv = iconv(ICONV, &inbuf, &inlen, &outbuf, &outlen);
390 iconv_close(ICONV);
391
392 if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %i): %i %i %i %"PRIiPTR"\n", __FILE__, __LINE__, (int)hc->SPR, (int)inlen, (int)(pos-hdr->AS.Header), reticonv );
393
394 if (reticonv == (size_t)(-1) ) {
395 perror("AXG - conversion of title failed!!!");
396 biosigERROR(hdr,B4C_FORMAT_UNSUPPORTED,"AXG - conversion of title failed");
397 return;
398 }
399 *outbuf=0;
400 #else
401 ++inbuf;
402 int i = min(MAX_LENGTH_LABEL, titleLen/2);
403 for (; i>0 ; i-- ) {
404 *outbuf= *inbuf;
405 inbuf += 2;
406 outbuf++;
407 }
408 outbuf = 0;
409 #endif
410 char *u1 = strrchr(hc->Label,'(');
411 char *u2 = strrchr(hc->Label,')');
412 if (u1 != NULL && u2 != NULL && u1 < u2) {
413 *u1 = 0;
414 *u2 = 0;
415 hc->PhysDimCode = PhysDimCode(u1+1);
416 }
417 }
418
419 // these might be reorganized below
420 hc->DigMax = 1e9;
421 hc->DigMin = -1e9;
422 hc->PhysMax = hc->DigMax;
423 hc->PhysMin = hc->DigMin;
424
425 hc->LeadIdCode = 0;
426 hc->Transducer[0] = 0;
427
428 hc->Cal = 1.0;
429 hc->Off = 0.0;
430
431 hc->TOffset = 0;
432 hc->HighPass = NAN;
433 hc->LowPass = NAN;
434 hc->Notch = NAN;
435 hc->Impedance = INFINITY;
436 hc->fZ = NAN;
437 hc->XYZ[0] = 0.0;
438 hc->XYZ[1] = 0.0;
439 hc->XYZ[2] = 0.0;
440 }
441
442 hdr->AS.rawdata = (uint8_t*)realloc( hdr->AS.rawdata, hdr->AS.bpb*hdr->SPR*hdr->NRec);
443
444 for (ns=0; ns < hdr->NS; ns++) {
445 CHANNEL_TYPE *hc = hdr->CHANNEL + ns;
446 hc->SPR = 0;
447 }
448 for (k=0; k < nCol; k++) {
449
450 ns = keyLabel[k];
451 CHANNEL_TYPE *hc = hdr->CHANNEL + ns;
452
453 if (hc->OnOff != 1) continue;
454
455 uint32_t i;
456 switch (hc->GDFTYP) {
457 case 3:
458 assert(TEMPCHANNEL[k].GDFTYP==4);
459 for (i=0; i < TEMPCHANNEL[k].SPR; i++) {
460 *(int16_t*)(hdr->AS.rawdata + hc->bi + (hc->SPR + i) * hdr->AS.bpb) = bei16p(TEMPCHANNEL[k].bufptr + i*2);
461 }
462 break;
463 case 5:
464 switch (TEMPCHANNEL[k].GDFTYP) {
465 case 4:
466 for (i=0; i < TEMPCHANNEL[k].SPR; i++) {
467 *(int32_t*)(hdr->AS.rawdata + hc->bi + (hc->SPR + i) * hdr->AS.bpb) = bei16p(TEMPCHANNEL[k].bufptr + i*2);
468 }
469 break;
470 case 5:
471 for (i=0; i < TEMPCHANNEL[k].SPR; i++) {
472 *(int32_t*)(hdr->AS.rawdata + hc->bi + (hc->SPR + i) * hdr->AS.bpb) = bei32p(TEMPCHANNEL[k].bufptr + i*4);
473 }
474 break;
475 default:
476 biosigERROR(hdr,B4C_FORMAT_UNSUPPORTED,"AXG - data conversion not supported ");
477 return;
478 }
479 break;
480 case 16:
481 switch (TEMPCHANNEL[k].GDFTYP) {
482 case 4:
483 for (i=0; i < TEMPCHANNEL[k].SPR; i++) {
484 *(float*)(hdr->AS.rawdata + hc->bi + (hc->SPR + i) * hdr->AS.bpb) = (float)bei16p(TEMPCHANNEL[k].bufptr + i*2);
485 }
486 break;
487 case 5:
488 for (i=0; i < TEMPCHANNEL[k].SPR; i++) {
489 *(float*)(hdr->AS.rawdata + hc->bi + (hc->SPR + i) * hdr->AS.bpb) = (float)bei32p(TEMPCHANNEL[k].bufptr + i*4);
490 }
491 break;
492 case 6:
493 for (i=0; i < TEMPCHANNEL[k].SPR; i++) {
494 *(float*)(hdr->AS.rawdata + hc->bi + (hc->SPR + i) * hdr->AS.bpb) = bef32p(TEMPCHANNEL[k].bufptr + i*4);
495 }
496 break;
497 case 10:
498 for (i=0; i < TEMPCHANNEL[k].SPR; i++) {
499 *(float*)(hdr->AS.rawdata + hc->bi + (hc->SPR + i) * hdr->AS.bpb) = bei16p(TEMPCHANNEL[k].bufptr + i*2) * TEMPCHANNEL[k].Cal + TEMPCHANNEL[k].Off;
500 }
501 break;
502 default:
503 biosigERROR(hdr,B4C_FORMAT_UNSUPPORTED,"AXG - data conversion not supported ");
504 return;
505 }
506 break;
507 case 17:
508 switch (TEMPCHANNEL[k].GDFTYP) {
509 case 4:
510 for (i=0; i < TEMPCHANNEL[k].SPR; i++) {
511 *(double*)(hdr->AS.rawdata + hc->bi + (hc->SPR + i) * hdr->AS.bpb) = (double)bei16p(TEMPCHANNEL[k].bufptr + i*2);
512 }
513 break;
514 case 5:
515 for (i=0; i < TEMPCHANNEL[k].SPR; i++) {
516 *(double*)(hdr->AS.rawdata + hc->bi + (hc->SPR + i) * hdr->AS.bpb) = (double)bei32p(TEMPCHANNEL[k].bufptr + i*4);
517 }
518 break;
519 case 6:
520 for (i=0; i < TEMPCHANNEL[k].SPR; i++) {
521 *(double*)(hdr->AS.rawdata + hc->bi + (hc->SPR + i) * hdr->AS.bpb) = (double)bef32p(TEMPCHANNEL[k].bufptr + i*4);
522 }
523 break;
524 case 7:
525 for (i=0; i < TEMPCHANNEL[k].SPR; i++) {
526 *(double*)(hdr->AS.rawdata + hc->bi + (hc->SPR + i) * hdr->AS.bpb) = bef64p(TEMPCHANNEL[k].bufptr + i*8);
527 }
528 break;
529 case 10:
530 for (i=0; i < TEMPCHANNEL[k].SPR; i++) {
531 *(double*)(hdr->AS.rawdata + hc->bi + (hc->SPR + i) * hdr->AS.bpb) = bei16p(TEMPCHANNEL[k].bufptr + i*2) * TEMPCHANNEL[k].Cal + TEMPCHANNEL[k].Off;
532 }
533 break;
534 default:
535 biosigERROR(hdr,B4C_FORMAT_UNSUPPORTED,"AXG - data conversion not supported ");
536 return;
537 }
538 break;
539 default:
540 biosigERROR(hdr,B4C_FORMAT_UNSUPPORTED,"AXG - unsupported target data type");
541 return;
542 }
543 hc->SPR += TEMPCHANNEL[k].SPR;
544 }
545
546 for (ns=0; ns < hdr->NS; ns++) {
547 CHANNEL_TYPE *hc = hdr->CHANNEL + ns;
548 hc->SPR = hdr->SPR;
549 }
550 // free intermediate data structure to reorganized column/trace to channels
551 if(TEMPCHANNEL) free(TEMPCHANNEL);
552 if(keyLabel) free(keyLabel);
553 if(ValLabel) free(ValLabel);
554
555 // data is stored on hdr->AS.rawdata in such a way that swapping must not be applied
556 hdr->FILE.LittleEndian = (__BYTE_ORDER == __LITTLE_ENDIAN);
557 hdr->AS.first = 0;
558 hdr->AS.length = (size_t)hdr->NRec;
559
560 // read Comments
561 size_t szComments = beu32p(pos);
562 char *inbuf = (char*)pos+4;
563 char *Comments = malloc(szComments+1);
564 char *outbuf = Comments;
565 size_t outlen = szComments+1;
566 size_t inlen = szComments;
567
568 iconv_t ICONV = iconv_open("UTF-8","UCS-2BE");
569 size_t reticonv = iconv(ICONV, &inbuf, &inlen, &outbuf, &outlen);
570 iconv_close(ICONV);
571 if (reticonv == (size_t)(-1) ) {
572 perror("AXG - conversion of comments failed!!!");
573 biosigERROR(hdr,B4C_FORMAT_UNSUPPORTED,"AXG - conversion of comments failed");
574 return;
575 }
576 Comments[outlen]=0;
577
578 if (VERBOSE_LEVEL >7)
579 fprintf(stdout,"\n=== COMMENT === \n %s\n",Comments);
580 pos += 4+szComments;
581
582
583 // read Notes
584 size_t szNotes = beu32p(pos);
585 inbuf = (char*)pos+4;
586 char *Notes = malloc(szNotes+1);
587 outbuf = Notes;
588 outlen = szNotes+1;
589 inlen = szNotes;
590
591 ICONV = iconv_open("UTF-8","UCS-2BE");
592 reticonv = iconv(ICONV, &inbuf, &inlen, &outbuf, &outlen);
593 iconv_close(ICONV);
594 if ( reticonv == (size_t)(-1) ) {
595 biosigERROR(hdr,B4C_FORMAT_UNSUPPORTED,"AXG - conversion of Notes failed");
596 return;
597 }
598 Notes[outlen]=0;
599
600 if (VERBOSE_LEVEL >7)
601 fprintf(stdout,"=== NOTES === \n %s\n",Notes);
602 pos += 4+szNotes;
603
604 /****** parse Date and Time ********/
605 struct tm T;
606 #ifdef __GLIBC__
607 strptime(strstr(Notes,"Created on ")+11, "%a %b %d %Y", &T);
608 strptime(strstr(Notes,"acquisition at ")+15, "%T", &T);
609 hdr->T0 = tm_time2gdf_time(&T);
610 #else
611 char DATE[30];
612 strncpy(DATE, strstr(Notes,"Created on ")+11, 30);
613 DATE[29] = 0;
614 strtok(DATE, "\n\r"); // cut at newline
615 char *tmp = strtok(DATE, " "); // day of week - skip
616
617 tmp = strtok(NULL, " "); // abreviated month name
618 T.tm_mon = month_string2int(tmp);
619
620 tmp = strtok(NULL, " "); // day of month
621 T.tm_mday = atoi(tmp);
622
623 tmp = strtok(NULL
624
625 , " "); // year
626 T.tm_year = atoi(tmp) - 1900;
627
628 strncpy(DATE, strstr(Notes,"acquisition at ")+15, 9);
629 DATE[9] = 0;
630 tmp = strtok(DATE, " :");
631 T.tm_hour = atoi(tmp);
632 tmp = strtok(NULL, " :");
633 T.tm_min = atoi(tmp);
634 tmp = strtok(NULL, " :");
635 T.tm_sec = atoi(tmp);
636
637 hdr->T0 = tm_time2gdf_time(&T);
638
639 #endif
640
641 hdr->AS.fpulse = Notes;
642 free(Comments);
643
644 if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %i)\n", __FILE__, __LINE__ );
645
646 }
647
648
649
650