LALPulsar  6.1.0.1-fe68b98
SFTReferenceLibrary.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2022 Karl Wette
3  * Copyright (C) 2004, 2005 Bruce Allen, Reinhard Prix
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with with program; see the file COPYING. If not, write to the
17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18  * MA 02110-1301 USA
19  */
20 
21 /**
22  * \addtogroup lalpulsar_sft
23  * \author Bruce Allen, Reinhard Prix
24  * \brief This is a reference library for the SFT data format \cite SFT-spec
25  */
26 
27 #include "config.h"
28 
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <math.h>
34 
35 #include <lal/XLALError.h>
36 
37 #include "SFTReferenceLibrary.h"
38 #include "SFTinternal.h"
39 
40 /*
41  The quantity below is: D800000000000000 (base-16) =
42  1101100000000000000000000000000000000000000000000000000000000000
43  (base-2). The primitive polynomial is x^64 + x^4 + x^3 + x + 1.
44 */
45 #define POLY64 0xd800000000000000ULL
46 #define TABLELEN 256
47 #define BLOCKSIZE 65536
48 
49 /* some local prototypes */
50 unsigned long long crc64( const unsigned char *data, unsigned int length, unsigned long long crc );
51 static void swap2( char *location );
52 static void swap4( char *location );
53 static void swap8( char *location );
54 static int validate_sizes( void );
55 static int validate_version( double version );
56 
57 /* The crc64 checksum of M bytes of data at address data is returned
58  by crc64(data, M, ~(0ULL)). Call the function multiple times to
59  compute the checksum of data made in contiguous chunks, setting
60  final argument to the previously accumulated checksum value. */
61 unsigned long long crc64( const unsigned char *data,
62  unsigned int length,
63  unsigned long long crc )
64 {
65 
66  unsigned long long CRCTable[TABLELEN];
67  unsigned int i;
68 
69  /* is there is no data, simply return previous checksum value */
70  if ( !length || !data ) {
71  return crc;
72  }
73 
74  /* initialize the CRC table for fast computation. We could keep
75  this table in memory to make the computation faster, but that is
76  not re-entrant for multi-threaded code.
77  */
78  for ( i = 0; i < TABLELEN; i++ ) {
79  int j;
80  unsigned long long part = i;
81  for ( j = 0; j < 8; j++ ) {
82  if ( part & 1 ) {
83  part = ( part >> 1 ) ^ POLY64;
84  } else {
85  part >>= 1;
86  }
87  }
88  CRCTable[i] = part;
89  }
90 
91  /* compute the CRC-64 code */
92  for ( i = 0; i < length; i++ ) {
93  unsigned long long temp1 = crc >> 8;
94  unsigned long long temp2 = CRCTable[( crc ^ ( unsigned long long ) data[i] ) & 0xff];
95  crc = temp1 ^ temp2;
96  }
97 
98  return crc;
99 }
100 
101 /* swap 2, 4 or 8 bytes. Point to low address */
102 static void swap2( char *location )
103 {
104  char tmp = *location;
105  *location = *( location + 1 );
106  *( location + 1 ) = tmp;
107  return;
108 }
109 
110 static void swap4( char *location )
111 {
112  char tmp = *location;
113  *location = *( location + 3 );
114  *( location + 3 ) = tmp;
115  swap2( location + 1 );
116  return;
117 }
118 
119 static void swap8( char *location )
120 {
121  char tmp = *location;
122  *location = *( location + 7 );
123  *( location + 7 ) = tmp;
124  tmp = *( location + 1 );
125  *( location + 1 ) = *( location + 6 );
126  *( location + 6 ) = tmp;
127  swap4( location + 2 );
128  return;
129 }
130 
131 /* this routine checks that the assumed sizes and structure packing
132  conventions of this code are valid. These checks could also be
133  done at compile time with #error statements */
134 static int validate_sizes( void )
135 {
136  if (
137  sizeof( char ) != 1 ||
138  sizeof( int ) != 4 ||
139  sizeof( long long ) != 8 ||
140  sizeof( struct headertag2 ) != 48
141  ) {
142  return SFTESIZEWRONG;
143  }
144 
145  return SFTNOERROR;
146 }
147 
148 
149 static int validate_version( double version )
150 {
151  for ( int v = MIN_SFT_VERSION; v <= MAX_SFT_VERSION; ++v ) {
152  if ( version == v ) {
153  return 1;
154  }
155  }
156  return 0;
157 }
158 
159 
160 /* translate return values from SFT routines into human-readable
161  character string error messages */
162 const char *SFTErrorMessage( int errorcode )
163 {
164 
165  switch ( errorcode ) {
166  case 0:
167  return "Success";
168  case SFTENULLFP:
169  return "SFT file pointer is NULL";
170  case SFTESEEK:
171  return "SFT fseek() failed in stream";
172  case SFTEREAD:
173  return "SFT fread() failed in stream";
174  case SFTEUNKNOWN:
175  return "SFT version in header is unknown";
176  case SFTEGPSNSEC:
177  return "SFT header GPS nsec not in range 0 to 10^9-1";
178  case SFTEBADCOMMENT:
179  return "SFT comment length not a multiple of 8";
180  case SFTEGETSTREAMPOS:
181  return "SFT fgetpos() failed: unable to save position of stream";
182  case SFTEBADCRC64:
183  return "SFT corrupted: CRC checksum in header does not match data";
185  return "SFT fsetpos() failed: unable to restore stream position";
186  case SFTENOMEM:
187  return "SFT calloc() failed: unable to allocate memory";
188  case SFTESIZEWRONG:
189  return "SFT sizeof() objects does not match assumptions";
190  case SFTEWRITE:
191  return "SFT fwrite() failed";
192  case SFTENULLPOINTER:
193  return "SFT library routine passed a null data pointer";
194  case SFTENONE:
195  return "SFT file empty (zero length)";
196  case SFTEHIDDENCOMMENT:
197  return "SFT comment contains data AFTER null character";
198  case SFTENONULLINCOMMENT:
199  return "SFT comment field is not null-terminated";
201  return "SFT GPS times not increasing between SFT blocks";
202  case SFTETBASECHANGES:
203  return "SFT time base changes between SFT blocks";
205  return "SFT first frequency index changes between SFT blocks";
206  case SFTENSAMPLESCHANGES:
207  return "SFT number of data samples changes between SFT blocks";
209  return "SFT window specification changes between SFT blocks";
211  return "SFT instrument changes between SFT blocks";
212  case SFTEVERSIONCHANGES:
213  return "SFT version changes between SFT blocks";
214  case SFTETBASENOTPOS:
215  return "SFT time base is not positive";
216  case SFTEFIRSTINDEXNEG:
217  return "SFT first frequency index is negative";
218  case SFTENSAMPLESNOTPOS:
219  return "SFT number of data samples is not positive";
221  return "SFT detector not one of A1 B1 E1 G1 H1 H2 K1 L1 N1 O1 P1 T1 V1 V2 X1";
222  case SFTEBEFOREDATA:
223  return "SFT data requested lies before available data";
224  case SFTEAFTERDATA:
225  return "SFT data requested lies after available data";
226  case SFTNOTFINITE:
227  return "SFT data contains a non-FINITE (+/- Inf, NaN) value";
228  }
229  return "SFT Error Code not recognized";
230 }
231 
232 /* return values: see header file
233  On return, this routine leaves the file pointer at the end of the SFT
234 */
235 int WriteSFT( FILE *fp, /* stream to write to */
236  int gps_sec, /* GPS sec of first sample */
237  int gps_nsec, /* GPS nsec of first sample */
238  double tbase, /* time baseline of SFTs */
239  int firstfreqindex, /* index of first frequency bin included in data (0=DC)*/
240  int nsamples, /* number of frequency bins to include in SFT */
241  const char *detector,/* channel-prefix defining detector */
242  unsigned short windowspec, /* SFT windowspec */
243  const char *comment, /* null-terminated comment string to include in SFT */
244  float *data /* points to nsamples x 2 x floats (Real/Imag) */
245  )
246 {
247  struct headertag2 header;
248  int comment_length, inc, i;
249  char pad[7];
250 
251  /* check that all data types have correct length */
252  if ( validate_sizes() ) {
253  return SFTESIZEWRONG;
254  }
255 
256  /* check that file pointer is valid */
257  if ( !fp ) {
258  return SFTENULLFP;
259  }
260 
261  /* check that nsec times are sensible */
262  if ( gps_nsec < 0 || gps_nsec > 999999999 ) {
263  return SFTEGPSNSEC;
264  }
265 
266  /* check that tbase is positive */
267  if ( tbase <= 0.0 ) {
268  return SFTETBASENOTPOS;
269  }
270 
271  /* check that first frequency index is non-negative */
272  if ( firstfreqindex < 0 ) {
273  return SFTEFIRSTINDEXNEG;
274  }
275 
276  /* check that number of samples is 1 or greater */
277  if ( nsamples <= 0 ) {
278  return SFTENSAMPLESNOTPOS;
279  }
280 
281  /* check that detector type is defined and data is present */
282  if ( !detector || !data ) {
283  return SFTENULLPOINTER;
284  }
285 
286  /* check that detector type is recognized */
287  if ( strlen( detector ) > 2 || unknownDetector( detector ) ) {
288  return SFTEINSTRUMENTUNKNOWN;
289  }
290 
291  /* comment length including null terminator to string must be an
292  integer multiple of eight bytes. comment==NULL means 'no
293  comment' */
294  if ( comment ) {
295  comment_length = strlen( comment ) + 1;
296  inc = ( 8 - ( comment_length % 8 ) ) % 8;
297  for ( i = 0; i < inc; i++ ) {
298  pad[i] = 0;
299  }
300  } else {
301  comment_length = 0;
302  inc = 0;
303  }
304 
305  /* fill out header */
306  header.version = MAX_SFT_VERSION;
307  header.gps_sec = gps_sec;
308  header.gps_nsec = gps_nsec;
309  header.tbase = tbase;
310  header.firstfreqindex = firstfreqindex;
311  header.nsamples = nsamples;
312  header.crc64 = 0;
313  header.detector[0] = detector[0];
314  header.detector[1] = detector[1];
315  header.windowspec = windowspec;
316  header.comment_length = comment_length + inc;
317 
318  /* compute CRC of header */
319  header.crc64 = crc64( ( const unsigned char * )&header, sizeof( header ), ~( 0ULL ) );
320 
321  /* compute CRC of comment */
322  header.crc64 = crc64( ( const unsigned char * )comment, comment_length, header.crc64 );
323 
324  /* compute CRC of comment padding */
325  header.crc64 = crc64( ( const unsigned char * )pad, inc, header.crc64 );
326 
327  /* compute CRC of data */
328  header.crc64 = crc64( ( const unsigned char * )data, nsamples * 2 * sizeof( float ), header.crc64 );
329 
330  /* write the header to file */
331  if ( 1 != fwrite( ( const void * )&header, sizeof( header ), 1, fp ) ) {
332  return SFTEWRITE;
333  }
334 
335  /* write the comment to file */
336  if ( comment_length != ( int )fwrite( ( const void * )comment, 1, comment_length, fp ) ) {
337  return SFTEWRITE;
338  }
339 
340  /* write comment padding to file */
341  if ( inc != ( int )fwrite( ( const void * )pad, 1, inc, fp ) ) {
342  return SFTEWRITE;
343  }
344 
345  /* write the data to the file. Data must be packed
346  REAL,IMAG,REAL,IMAG,... */
347  if ( nsamples != ( int )fwrite( ( const void * )data, 2 * sizeof( float ), nsamples, fp ) ) {
348  return SFTEWRITE;
349  }
350 
351  return SFTNOERROR;
352 }
353 
354 /* On return this routine leaves the stream in the same
355  place as when the routine was called */
356 int ReadSFTHeader( FILE *fp, /* stream to read */
357  struct headertag2 *info, /* address to return header */
358  char **comment, /* if non-NULL, put pointer to comment */
359  int *swapendian, /* set nonzero if data in reverse endian order */
360  int validate ) /* validate checksum of the file */
361 {
362  struct headertag2 header, header_unswapped;
363  int swap = 0;
364  int what, retval = 0;
365  fpos_t streamposition;
366  char *mycomment = NULL;
367 
368  /* check that all data types have correct length */
369  if ( validate_sizes() ) {
370  return SFTESIZEWRONG;
371  }
372 
373  /* check that pointers are valid */
374  if ( !fp ) {
375  return SFTENULLFP;
376  }
377 
378  if ( !info || !swapendian ) {
379  return SFTENULLPOINTER;
380  }
381 
382  /* save stream position */
383  if ( fgetpos( fp, &streamposition ) ) {
384  return SFTEGETSTREAMPOS;
385  }
386 
387  /* read in header. Note that the second and third arguments to fread() are reversed
388  from conventional practice, so that we can see if the file is zero length */
389  if ( sizeof( header ) != ( what = fread( ( void * )&header, 1, sizeof( header ), fp ) ) ) {
390  if ( !what && feof( fp ) ) {
391  retval = SFTENONE;
392  } else {
393  retval = SFTEREAD;
394  }
395  goto error;
396  }
397 
398  /* save an unswapped copy */
399  header_unswapped = header;
400 
401  /* check endian ordering, and swap if needed */
402  if ( !validate_version( header.version ) ) {
403  swap8( ( char * )&header.version );
404  swap4( ( char * )&header.gps_sec );
405  swap4( ( char * )&header.gps_nsec );
406  swap8( ( char * )&header.tbase );
407  swap4( ( char * )&header.firstfreqindex );
408  swap4( ( char * )&header.nsamples );
409  swap8( ( char * )&header.crc64 );
410  swap2( ( char * )&header.windowspec );
411  swap4( ( char * )&header.comment_length );
412  swap = 1;
413  }
414 
415  /* check if header version is recognized */
416  if ( !validate_version( header.version ) ) {
417  retval = SFTEUNKNOWN;
418  goto error;
419  }
420 
421  if ( header.comment_length % 8 ) {
422  retval = SFTEBADCOMMENT;
423  goto error;
424  }
425 
426  /* check that number of samples is 1 or greater. We do this check
427  before calculating CRC since the number of values to CRC check
428  must be known first */
429  if ( header.nsamples <= 0 ) {
430  retval = SFTENSAMPLESNOTPOS;
431  goto error;
432  }
433 
434  /* validate crc64 checksum ?? Do this BEFORE other checks since if
435  a problem occurs it is more likely file corruption than a bad
436  SFT */
437  if ( validate ) {
438  unsigned long long crc;
439  unsigned long long crc64save = header.crc64;
440  int total_length = header.comment_length + 2 * sizeof( float ) * header.nsamples;
441  char block[BLOCKSIZE];
442  fpos_t streamposition2;
443  int i, tocheck, foundhidden = 0, comment_left = header.comment_length, foundnull = !comment_left;
444 
445  /* save stream position */
446  if ( fgetpos( fp, &streamposition2 ) ) {
447  retval = SFTEGETSTREAMPOS;
448  goto error;
449  }
450 
451  /* compute CRC of header */
452  header_unswapped.crc64 = 0ULL;;
453  crc = crc64( ( unsigned char * )&header_unswapped, sizeof( header_unswapped ), ~( 0ULL ) );
454 
455  /* read data in lengths of BLOCKSIZE, computing CRC */
456  while ( total_length > 0 ) {
457  /* read either BLOCKSIZE or amount remaining */
458  int toread = ( BLOCKSIZE < total_length ) ? BLOCKSIZE : total_length;
459  if ( toread != ( int )fread( block, 1, toread, fp ) ) {
460  retval = SFTEREAD;
461  goto error;
462  }
463  total_length -= toread;
464  crc = crc64( ( unsigned char * )block, toread, crc );
465 
466  /* check to see if comment contains NULL termination character
467  and no hidden characters */
468  tocheck = ( comment_left < toread ) ? comment_left : toread;
469  for ( i = 0; i < tocheck; i++ ) {
470  if ( !block[i] ) {
471  foundnull = 1;
472  }
473  if ( foundnull && block[i] ) {
474  foundhidden = 1;
475  }
476  }
477  comment_left -= tocheck;
478  }
479 
480  /* check that checksum is consistent */
481  if ( crc != crc64save ) {
482  XLALPrintInfo( "%s: CRC64 computes as %llu\n", __func__, crc );
483  XLALPrintInfo( "%s: CRC64 in SFT is %llu\n", __func__, crc64save );
484  retval = SFTEBADCRC64;
485  goto error;
486  }
487 
488  /* check that comment has correct NULL termination */
489  if ( !foundnull ) {
490  retval = SFTENONULLINCOMMENT;
491  goto error;
492  }
493 
494  /* check that comment has no hidden characters */
495  if ( foundhidden ) {
496  retval = SFTEHIDDENCOMMENT;
497  goto error;
498  }
499 
500  /* return to position just after header to read comment if desired */
501  if ( fsetpos( fp, &streamposition2 ) ) {
502  retval = SFTERESTORESTREAMPOS;
503  goto error;
504  }
505  }
506 
507  /* check that time stamps are in a valid range */
508  if ( header.gps_nsec < 0 || header.gps_nsec > 999999999 ) {
509  retval = SFTEGPSNSEC;
510  goto error;
511  }
512 
513  /* check that tbase is positive */
514  if ( header.tbase <= 0.0 ) {
515  retval = SFTETBASENOTPOS;
516  goto error;
517  }
518 
519  /* check that first frequency index is non-negative */
520  if ( header.firstfreqindex < 0 ) {
521  retval = SFTEFIRSTINDEXNEG;
522  goto error;
523  }
524 
525  /* check that detector type is known */
526  if ( unknownDetector( header.detector ) ) {
527  return SFTEINSTRUMENTUNKNOWN;
528  }
529 
530  /* if user has asked for comment, store it */
531  if ( comment && header.comment_length ) {
532  int i;
533 
534  /* first allocate memory for storing the comment */
535  if ( !( mycomment = calloc( header.comment_length, 1 ) ) ) {
536  retval = SFTENOMEM;
537  goto error;
538  }
539 
540  /* now read the comment into memory */
541  if ( header.comment_length != ( int )fread( mycomment, 1, header.comment_length, fp ) ) {
542  free( mycomment );
543  mycomment = NULL;
544  retval = SFTEREAD;
545  goto error;
546  }
547 
548  /* check that the comment is null-terminated and contains no
549  messages 'hidden' after a NULL character */
550  retval = SFTENONULLINCOMMENT;
551  for ( i = 0; i < header.comment_length; i++ ) {
552  if ( !mycomment[i] ) {
553  retval = 0;
554  }
555  if ( !retval && mycomment[i] ) {
556  retval = SFTEHIDDENCOMMENT;
557  break;
558  }
559  }
560  if ( retval ) {
561  free( mycomment );
562  mycomment = NULL;
563  goto error;
564  }
565  }
566 
567 error:
568  /* restore stream pointer to the correct position */
569  if ( fsetpos( fp, &streamposition ) ) {
570  retval = SFTERESTORESTREAMPOS;
571  }
572 
573  if ( retval ) {
574  return retval;
575  }
576 
577  /* no errors found: now set return values and return */
578  *swapendian = swap;
579 
580  if ( comment )
581  /* note: mycomment may be NULL if there is NO comment */
582  {
583  *comment = mycomment;
584  }
585 
586  /* return header-info */
587  *info = header;
588 
589  return SFTNOERROR;
590 }
591 
592 
593 
594 int ReadSFTData( FILE *fp, /* data file. Position left unchanged on return */
595  float *data, /* location where data should be written */
596  int firstbin, /* first frequency bin to read from data set */
597  int nsamples, /* number of frequency bin samples to retrieve */
598  char **comment, /* if non-NULL, will contain pointer to comment string */
599  struct headertag2 *info /* if non-NULL, will contain header information */
600  )
601 {
602  fpos_t streamposition;
603  int retval = 0, swapendian;
604  int seekforward;
605  struct headertag2 myinfo;
606 
607  /* check for null pointers */
608  if ( !fp ) {
609  return SFTENULLFP;
610  }
611 
612  if ( !data && nsamples ) {
613  return SFTENULLPOINTER;
614  }
615 
616  /* save position of stream */
617  if ( fgetpos( fp, &streamposition ) ) {
618  return SFTEGETSTREAMPOS;
619  }
620 
621  /* read header of SFT */
622  if ( ( retval = ReadSFTHeader( fp, &myinfo, comment, &swapendian, 0 ) ) ) {
623  goto error;
624  }
625 
626  /* sanity checks -- do we ask for data before the first frequency bin */
627  if ( firstbin < myinfo.firstfreqindex ) {
628  retval = SFTEBEFOREDATA;
629  goto error;
630  }
631 
632  /* warning, after this subtraction firstbin contains the offset to
633  the first requested bin! */
634  firstbin -= myinfo.firstfreqindex;
635 
636  /* sanity checks -- do we ask for data after the last frequency bin */
637  if ( ( firstbin + nsamples ) > myinfo.nsamples ) {
638  retval = SFTEAFTERDATA;
639  goto error;
640  }
641 
642  /* seek to start of data (skip comment if present) */
643  seekforward = sizeof( struct headertag2 ) + myinfo.comment_length + firstbin * 2 * sizeof( float );
644  if ( fseek( fp, seekforward, SEEK_CUR ) ) {
645  retval = SFTESEEK;
646  goto error2;
647  }
648 
649  /* read in the data */
650  if ( nsamples != ( int )fread( ( void * )data, 2 * sizeof( float ), nsamples, fp ) ) {
651  retval = SFTEREAD;
652  goto error2;
653  }
654 
655  /* byte reverse the data if necessary */
656  if ( swapendian ) {
657  int i;
658  for ( i = 0; i < 2 * nsamples; i++ ) {
659  swap4( ( char * )( data + i ) );
660  }
661  }
662 
663 error2:
664  /* free storage for the comemnt string */
665  if ( retval && comment && *comment ) {
666  free( *comment );
667  *comment = NULL;
668  }
669 
670 error:
671  /* return to starting position in stream */
672  if ( fsetpos( fp, &streamposition ) ) {
673  return SFTERESTORESTREAMPOS;
674  }
675 
676  /* if no errors, return header information */
677  if ( info && !retval ) {
678  *info = myinfo;
679  }
680 
681  return retval;
682 }
683 
684 /* This routine returns zero if the two headers contain consistent
685  information, else an error code if they are not consistent */
686 int CheckSFTHeaderConsistency( struct headertag2 *headerone, /* pointer to earlier header */
687  struct headertag2 *headertwo /* pointer to later header */
688  )
689 {
690  /* check for null pointer */
691  if ( !headerone || !headertwo ) {
692  return SFTENULLPOINTER;
693  }
694 
695  /* Same version number */
696  if ( headerone->version != headertwo->version ) {
697  return SFTEVERSIONCHANGES;
698  }
699 
700  /* GPS times increasing */
701  if ( headerone->gps_sec > headertwo->gps_sec || ( headerone->gps_sec == headertwo->gps_sec && headerone->gps_nsec >= headertwo->gps_nsec ) ) {
702  return SFTEGPSNOTINCREASING;
703  }
704 
705  /* Time base the same */
706  if ( headerone->tbase != headertwo->tbase ) {
707  return SFTETBASECHANGES;
708  }
709 
710  /* First frequency index the same */
711  if ( headerone->firstfreqindex != headertwo->firstfreqindex ) {
712  return SFTEFIRSTINDEXCHANGES;
713  }
714 
715  /* Number of samples the same */
716  if ( headerone->nsamples != headertwo->nsamples ) {
717  return SFTENSAMPLESCHANGES;
718  }
719 
720  /* check for identical detectors */
721  if ( ( headerone->detector[0] != headertwo->detector[0] ) || ( headerone->detector[1] != headertwo->detector[1] ) ) {
722  return SFTEINSTRUMENTCHANGES;
723  }
724 
725  /* Window specification the same */
726  if ( headerone->windowspec != headertwo->windowspec ) {
727  return SFTEWINDOWSPECCHANGES;
728  }
729 
730  return SFTNOERROR;
731 }
732 
733 /* check that channel-prefix defines a 'known' detector. The list of
734  * known detectors implemented here for now follows the list in
735  * Appendix D of LIGO-T970130-F-E:
736  *
737  * returns 0 if known, error code otherwise */
738 int unknownDetector( const char *detector )
739 {
740  int i;
741  const char *knownDetectors[] = {
742  "A1", /* ALLEGRO */
743  "B1", /* NIOBE */
744  "E1", /* ET */
745  "G1", /* GEO_600 */
746  "H1", /* LHO_4k */
747  "H2", /* LHO_2k */
748  "K1", /* KAGRA */
749  "L1", /* LLO_4k */
750  "N1", /* Nautilus */
751  "O1", /* AURIGA */
752  "P1", /* CIT_40 */
753  "T1", /* TAMA_300 */
754  "V1", /* Virgo (3km) */
755  "V2", /* Virgo_CITF */
756  "X1", /* RXTE */
757  NULL
758  };
759 
760  if ( !detector ) {
761  return SFTENULLPOINTER;
762  }
763 
764  for ( i = 0; knownDetectors[i]; i++ ) {
765  if ( knownDetectors[i][0] == detector[0] && knownDetectors[i][1] == detector[1] ) {
766  return 0;
767  }
768  }
769 
770  return SFTEINSTRUMENTUNKNOWN;
771 
772 } /* unknownDetector() */
773 
774 
775 /**
776  * Verify that the contents of a SFT file are valid.
777  *
778  * \return 0 if all SFTs are valid.
779  * The exit status will be non-zero if any of the validity checks do not pass.
780  * Error codes are defined in SFTReferenceLibrary.h .
781  *
782  * This has been extracted from lalpulsar_SFTvalidate,
783  * original author: Bruce Allen
784  */
785 int
786 ValidateSFTFile( const char *fname )
787 {
788 
789  FILE *fp;
790  int err = 0;
791  float *data = NULL;
792 
793  /* clear error status */
794  errno = 0;
795 
796  /* open the file */
797  if ( !( fp = fopen( fname, "r" ) ) ) {
798  XLALPrintError( "%s: Unable to open %s", __func__, fname );
799  if ( errno ) {
800  XLALPrintError( "%s: errno=%i (%s)", __func__, errno, strerror( errno ) );
801  }
802  return SFTENULLFP;
803  }
804 
805  /* and read successive SFTs blocks from the file and validate CRC
806  checksums */
807  struct headertag2 lastinfo;
808  memset( &lastinfo, 0, sizeof( lastinfo ) );
809  for ( int count = 0; 1; count++ ) {
810  struct headertag2 info;
811  int swapendian, move, j;
812 
813  err = ReadSFTHeader( fp, &info, NULL, &swapendian, 1 );
814 
815  /* at end of SFT file or merged SFT file blocks */
816  if ( err == SFTENONE && count ) {
817  err = 0;
818  break;
819  }
820 
821  /* SFT was invalid: say why */
822  if ( err ) {
823  XLALPrintError( "%s: %s is not a valid SFT (%s)\n", __func__, fname, SFTErrorMessage( err ) );
824  if ( errno ) {
825  XLALPrintError( "%s: errno=%i (%s)", __func__, errno, strerror( errno ) );
826  }
827  break;
828  }
829 
830  /* check that various bits of header information are consistent */
831  if ( count && ( err = CheckSFTHeaderConsistency( &lastinfo, &info ) ) ) {
832  XLALPrintError( "%s: %s is not a valid SFT (%s)\n", __func__, fname, SFTErrorMessage( err ) );
833  if ( errno ) {
834  XLALPrintError( "%s: errno=%i (%s)", __func__, errno, strerror( errno ) );
835  }
836  break;
837  }
838 
839  /* check that data appears valid */
840  data = ( float * )realloc( ( void * )data, info.nsamples * 4 * 2 );
841  if ( !data ) {
842  errno = SFTENULLPOINTER;
843  XLALPrintError( "%s: ran out of memory at %s (%s)\n", __func__, fname, SFTErrorMessage( err ) );
844  if ( errno ) {
845  XLALPrintError( "%s: errno=%i (%s)", __func__, errno, strerror( errno ) );
846  }
847  break;
848  }
849 
850  err = ReadSFTData( fp, data, info.firstfreqindex, info.nsamples, /*comment*/ NULL, /*headerinfo */ NULL );
851  if ( err ) {
852  XLALPrintError( "%s: %s is not a valid SFT (%s)\n", __func__, fname, SFTErrorMessage( err ) );
853  if ( errno ) {
854  XLALPrintError( "%s: errno=%i (%s)", __func__, errno, strerror( errno ) );
855  }
856  break;
857  }
858 
859  for ( j = 0; j < info.nsamples; j++ ) {
860  if ( !isfinite( data[2 * j] ) || !isfinite( data[2 * j + 1] ) ) {
861  XLALPrintError( "%s: %s is not a valid SFT (data infinite at freq bin %d)\n", __func__, fname, j + info.firstfreqindex );
862  err = SFTNOTFINITE;
863  break;
864  }
865  }
866 
867  /* keep copy of header for comparison the next time */
868  lastinfo = info;
869 
870  /* Move forward to next SFT in merged file */
871  move = sizeof( struct headertag2 ) + info.nsamples * 2 * sizeof( float ) + info.comment_length;
872  fseek( fp, move, SEEK_CUR );
873  }
874 
875  /* cleanup */
876  fclose( fp );
877  free( data );
878 
879  return err;
880 
881 } /* ValidateSFTFile */
#define __func__
log an I/O error, i.e.
int j
static int validate_sizes(void)
static void swap2(char *location)
static void swap4(char *location)
unsigned long long crc64(const unsigned char *data, unsigned int length, unsigned long long crc)
static int validate_version(double version)
#define TABLELEN
static void swap8(char *location)
#define POLY64
#define BLOCKSIZE
Internal SFT types and functions.
#define MAX_SFT_VERSION
Definition: SFTinternal.h:54
#define MIN_SFT_VERSION
Definition: SFTinternal.h:53
const char * comment
Definition: SearchTiming.c:94
#define SFTENULLPOINTER
#define SFTENONE
#define SFTERESTORESTREAMPOS
#define SFTEVERSIONCHANGES
#define SFTEBADCRC64
#define SFTNOTFINITE
const char * SFTErrorMessage(int errorcode)
#define SFTETBASENOTPOS
int CheckSFTHeaderConsistency(struct headertag2 *headerone, struct headertag2 *headertwo)
#define SFTEHIDDENCOMMENT
#define SFTEUNKNOWN
#define SFTNOERROR
#define SFTETBASECHANGES
int unknownDetector(const char *detector)
#define SFTENSAMPLESCHANGES
#define SFTEFIRSTINDEXCHANGES
#define SFTENOMEM
#define SFTEWINDOWSPECCHANGES
#define SFTESEEK
int ReadSFTHeader(FILE *fp, struct headertag2 *info, char **comment, int *swapendian, int validate)
#define SFTEBEFOREDATA
#define SFTENULLFP
int ValidateSFTFile(const char *fname)
Verify that the contents of a SFT file are valid.
#define SFTEAFTERDATA
#define SFTENONULLINCOMMENT
#define SFTEINSTRUMENTUNKNOWN
#define SFTEGPSNSEC
#define SFTESIZEWRONG
#define SFTEGPSNOTINCREASING
int WriteSFT(FILE *fp, int gps_sec, int gps_nsec, double tbase, int firstfreqindex, int nsamples, const char *detector, unsigned short windowspec, const char *comment, float *data)
#define SFTEBADCOMMENT
#define SFTENSAMPLESNOTPOS
int ReadSFTData(FILE *fp, float *data, int firstbin, int nsamples, char **comment, struct headertag2 *info)
#define SFTEREAD
#define SFTEWRITE
#define SFTEINSTRUMENTCHANGES
#define SFTEFIRSTINDEXNEG
#define SFTEGETSTREAMPOS
int int int XLALPrintInfo(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
long long count
Definition: hwinject.c:371
unsigned long long crc64
unsigned short windowspec
double pad