📄 fileutils.c
字号:
/*************************************************************************** * * Routines to manage files of Mini-SEED. * * Written by Chad Trabant, ORFEUS/EC-Project MEREDIAN * * modified: 2008.161 ***************************************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <errno.h>#include "libmseed.h"/* Byte stream length for read-ahead header fingerprinting */#define NEXTHDRLEN 48static int ms_readpackinfo (int packtype, FILE *stream);static int ms_fread (char *buf, int size, int num, FILE *stream);static int ms_ateof (FILE *stream);/* Pack type parameters for the 8 defined types: * [type] : [hdrlen] [sizelen] [chksumlen] */int8_t packtypes[9][3] = { { 0, 0, 0 }, { 8, 8, 8 }, { 11, 8, 8 }, { 11, 8, 8 }, { 11, 8, 8 }, { 11, 8, 8 }, { 13, 8, 8 }, { 15, 8, 8 }, { 22, 15, 10 }};/* Initialize the global file reading parameters */MSFileParam gMSFileParam = {NULL, NULL, "", 1, MINRECLEN, 0, 0, 0, 0};/********************************************************************** * ms_readmsr: * * This routine is a simple wrapper for ms_readmsr_r() that uses the * global file reading parameters. This routine is not thread safe * and cannot be used to read more than one file at a time. * * See the comments with ms_readmsr_r() for return values and further * description of arguments. *********************************************************************/intms_readmsr (MSRecord **ppmsr, char *msfile, int reclen, off_t *fpos, int *last, flag skipnotdata, flag dataflag, flag verbose){ MSFileParam *msfp = &gMSFileParam; return ms_readmsr_r (&msfp, ppmsr, msfile, reclen, fpos, last, skipnotdata, dataflag, verbose);} /* End of ms_readmsr() *//********************************************************************** * ms_readmsr_r: * * This routine will open and read, with subsequent calls, all * Mini-SEED records in specified file. * * All static file reading parameters are stored in a MSFileParam * struct and returned (via a pointer to a pointer) for the calling * routine to use in subsequent calls. A MSFileParam struct will be * allocated if necessary. This routine is thread safe and can be * used to read multiple files in parallel as long as the file reading * parameters are managed appropriately. * * If reclen is 0 the length of the first record is automatically * detected, all subsequent records are then expected to have the same * length as the first. * * If reclen is negative the length of every record is automatically * detected. * * For auto detection of record length the record must include a 1000 * blockette. This routine will search up to 8192 bytes into the * record for the 1000 blockette. * * If *fpos is not NULL it will be updated to reflect the file * position (offset from the beginning in bytes) from where the * returned record was read. * * If *last is not NULL it will be set to 1 when the last record in * the file is being returned, otherwise it will be 0. * * If the skipnotdata flag is true any data chunks read that do not * have vald data record indicators (D, R, Q, M, etc.) will be skipped. * * dataflag will be passed directly to msr_unpack(). * * After reading all the records in a file the controlling program * should call it one last time with msfile set to NULL. This will * close the file and free allocated memory. * * Returns MS_NOERROR and populates an MSRecord struct at *ppmsr on * successful read, returns MS_ENDOFFILE on EOF, otherwise returns a * libmseed error code (listed in libmseed.h) and *ppmsr is set to * NULL. *********************************************************************/intms_readmsr_r (MSFileParam **ppmsfp, MSRecord **ppmsr, char *msfile, int reclen, off_t *fpos, int *last, flag skipnotdata, flag dataflag, flag verbose){ MSFileParam *msfp; int packdatasize; int autodetexp = 8; int prevreadlen; int detsize; int retcode = MS_NOERROR; if ( ! ppmsr ) return MS_GENERROR; if ( ! ppmsfp ) return MS_GENERROR; msfp = *ppmsfp; /* Initialize the file read parameters if needed */ if ( ! msfp ) { msfp = (MSFileParam *) malloc (sizeof (MSFileParam)); if ( msfp == NULL ) { ms_log (2, "ms_readmsr_r(): Cannot allocate memory\n"); return MS_GENERROR; } /* Redirect the supplied pointer to the allocted params */ *ppmsfp = msfp; msfp->fp = NULL; msfp->rawrec = NULL; msfp->filename[0] = '\0'; msfp->autodet = 1; msfp->readlen = MINRECLEN; msfp->packtype = 0; msfp->packhdroffset = 0; msfp->filepos = 0; msfp->recordcount = 0; } /* When cleanup is requested */ if ( msfile == NULL ) { msr_free (ppmsr); if ( msfp->fp != NULL ) fclose (msfp->fp); if ( msfp->rawrec != NULL ) free (msfp->rawrec); /* If the file parameters are the global parameters reset them */ if ( *ppmsfp == &gMSFileParam ) { gMSFileParam.fp = NULL; gMSFileParam.rawrec = NULL; gMSFileParam.filename[0] = '\0'; gMSFileParam.autodet = 1; gMSFileParam.readlen = MINRECLEN; gMSFileParam.packtype = 0; gMSFileParam.packhdroffset = 0; gMSFileParam.filepos = 0; gMSFileParam.recordcount = 0; } /* Otherwise free the MSFileParam */ else { free (*ppmsfp); *ppmsfp = NULL; } return MS_NOERROR; } /* Sanity check: track if we are reading the same file */ if ( msfp->fp && strncmp (msfile, msfp->filename, sizeof(msfp->filename)) ) { ms_log (2, "ms_readmsr() called with a different file name before being reset\n"); /* Close previous file and reset needed variables */ if ( msfp->fp != NULL ) fclose (msfp->fp); msfp->fp = NULL; msfp->autodet = 1; msfp->readlen = MINRECLEN; msfp->packtype = 0; msfp->packhdroffset = 0; msfp->filepos = 0; msfp->recordcount = 0; } /* Open the file if needed, redirect to stdin if file is "-" */ if ( msfp->fp == NULL ) { /* Store the filename for tracking */ strncpy (msfp->filename, msfile, sizeof(msfp->filename) - 1); msfp->filename[sizeof(msfp->filename) - 1] = '\0'; if ( strcmp (msfile, "-") == 0 ) { msfp->fp = stdin; } else if ( (msfp->fp = fopen (msfile, "rb")) == NULL ) { ms_log (2, "Cannot open file: %s (%s)\n", msfile, strerror (errno)); msr_free (ppmsr); return MS_GENERROR; } } /* Force the record length if specified */ if ( reclen > 0 && msfp->autodet ) { msfp->readlen = reclen; msfp->autodet = 0; msfp->rawrec = (char *) malloc (msfp->readlen); if ( msfp->rawrec == NULL ) { ms_log (2, "ms_readmsr_r(): Cannot allocate memory\n"); return MS_GENERROR; } } /* If reclen is negative reset readlen for autodetection */ if ( reclen < 0 ) msfp->readlen = (unsigned int) 1 << autodetexp; /* Zero the last record indicator */ if ( last ) *last = 0; /* Autodetect the record length */ if ( msfp->autodet || reclen < 0 ) { detsize = 0; prevreadlen = 0; while ( detsize <= 0 && msfp->readlen <= 8192 ) { msfp->rawrec = (char *) realloc (msfp->rawrec, msfp->readlen); if ( msfp->rawrec == NULL ) { ms_log (2, "ms_readmsr_r(): Cannot reallocate memory\n"); return MS_GENERROR; } /* Read packed file info */ if ( msfp->packtype && msfp->filepos == msfp->packhdroffset ) { if ( (packdatasize = ms_readpackinfo (msfp->packtype, msfp->fp)) <= 0 ) { if ( msfp->fp ) { fclose (msfp->fp); msfp->fp = NULL; } msr_free (ppmsr); if ( msfp->rawrec ) { free (msfp->rawrec); msfp->rawrec = NULL; } if ( packdatasize == 0 ) return MS_ENDOFFILE; else return MS_GENERROR; } msfp->filepos = lmp_ftello (msfp->fp); /* File position + data size */ msfp->packhdroffset = msfp->filepos + packdatasize; if ( verbose > 1 ) ms_log (1, "Read packed file header at offset %lld (%d bytes follow)\n", (long long int) (msfp->filepos - packtypes[msfp->packtype][0] - packtypes[msfp->packtype][2]), packdatasize); } /* Read data into record buffer */ if ( (ms_fread (msfp->rawrec + prevreadlen, 1, (msfp->readlen - prevreadlen), msfp->fp)) < (msfp->readlen - prevreadlen) ) { if ( ! feof (msfp->fp) ) { ms_log (2, "Short read at %d bytes during length detection\n", msfp->readlen); retcode = MS_GENERROR; } else { retcode = MS_ENDOFFILE; } if ( msfp->recordcount == 0 ) { if ( verbose > 0 ) ms_log (2, "%s: No data records read, not SEED?\n", msfile); retcode = MS_NOTSEED; } if ( msfp->fp ) { fclose (msfp->fp); msfp->fp = NULL; } msr_free (ppmsr); if ( msfp->rawrec ) { free (msfp->rawrec); msfp->rawrec = NULL; } return retcode; } msfp->filepos = lmp_ftello (msfp->fp); /* Determine record length: * If packed file and we are at the next info, length is implied. * Otherwise use ms_find_reclen() */ if ( msfp->packtype && msfp->packhdroffset == msfp->filepos ) { detsize = msfp->readlen; break; } else if ( (detsize = ms_find_reclen (msfp->rawrec, msfp->readlen, msfp->fp)) > 0 ) { break; } /* Test for packed file signature at the beginning of the file */ if ( *(msfp->rawrec) == 'P' && msfp->filepos == MINRECLEN && detsize == -1 ) { msfp->packtype = 0; /* Set pack spacer length according to type */ if ( ! memcmp ("PED", msfp->rawrec, 3) ) msfp->packtype = 1; else if ( ! memcmp ("PSD", msfp->rawrec, 3) ) msfp->packtype = 2; else if ( ! memcmp ("PLC", msfp->rawrec, 3) ) msfp->packtype = 6; else if ( ! memcmp ("PQI", msfp->rawrec, 3) ) msfp->packtype = 7; else if ( ! memcmp ("PLS", msfp->rawrec, 3) ) msfp->packtype = 8; /* Read first pack header section, compensate for "pack identifier" (10 bytes) */ if ( msfp->packtype ) { char hdrstr[30]; if ( verbose > 0 ) ms_log (1, "Detected packed file (%3.3s: type %d)\n", msfp->rawrec, msfp->packtype); /* Read pack length from end of pack header accounting for initial 10 characters */ memset (hdrstr, 0, sizeof(hdrstr)); memcpy (hdrstr, msfp->rawrec + (packtypes[msfp->packtype][0] + 10 - packtypes[msfp->packtype][1]), packtypes[msfp->packtype][1]); sscanf (hdrstr, " %d", &packdatasize); /* Next pack header offset: Pack ID + pack hdr + data size */ msfp->packhdroffset = 10 + packtypes[msfp->packtype][0] + packdatasize; if ( verbose > 1 ) ms_log (1, "Read packed file header at beginning of file (%d bytes follow)\n", packdatasize); } } /* Skip if data record or packed file not detected */ if ( detsize == -1 && skipnotdata && ! msfp->packtype ) { if ( verbose > 1 ) { if ( MS_ISVALIDBLANK((char *)msfp->rawrec) ) ms_log (1, "Skipped %d bytes of blank/noise record at byte offset %lld\n", msfp->readlen, (long long) msfp->filepos - msfp->readlen); else ms_log (1, "Skipped %d bytes of non-data record at byte offset %lld\n", msfp->readlen, (long long) msfp->filepos - msfp->readlen); } } /* Otherwise read more */ else { /* Compensate for first packed file "identifier" section (10 bytes) */ if ( msfp->filepos == MINRECLEN && msfp->packtype ) { /* Shift first data record to beginning of buffer */ memmove (msfp->rawrec, msfp->rawrec + (packtypes[msfp->packtype][0] + 10), msfp->readlen - (packtypes[msfp->packtype][0] + 10)); prevreadlen = msfp->readlen - (packtypes[msfp->packtype][0] + 10); } /* Increase read length to the next record size up */ else { prevreadlen = msfp->readlen; autodetexp++; msfp->readlen = (unsigned int) 1 << autodetexp; } } } if ( detsize <= 0 ) { ms_log (2, "Cannot detect record length at byte offset %lld: %s\n", (long long) msfp->filepos - msfp->readlen, msfile); if ( msfp->fp ) { fclose (msfp->fp); msfp->fp = NULL; } msr_free (ppmsr); if ( msfp->rawrec ) { free (msfp->rawrec); msfp->rawrec = NULL; } return MS_NOTSEED; } msfp->autodet = 0; if ( verbose > 0 ) ms_log (1, "Detected record length of %d bytes\n", detsize); if ( detsize < MINRECLEN || detsize > MAXRECLEN ) { ms_log (2, "Detected record length is out of range: %d\n", detsize); if ( msfp->fp ) { fclose (msfp->fp); msfp->fp = NULL; } msr_free (ppmsr); if ( msfp->rawrec ) { free (msfp->rawrec); msfp->rawrec = NULL; } return MS_OUTOFRANGE; } msfp->rawrec = (char *) realloc (msfp->rawrec, detsize); if ( msfp->rawrec == NULL ) { ms_log (2, "ms_readmsr_r(): Cannot allocate memory\n"); return MS_GENERROR; } /* Read the rest of the first record */ if ( (detsize - msfp->readlen) > 0 ) { if ( (ms_fread (msfp->rawrec+msfp->readlen, 1, detsize-msfp->readlen, msfp->fp)) < (detsize-msfp->readlen) ) { if ( ! feof (msfp->fp) ) { ms_log (2, "Short read at %d bytes during length detection\n", msfp->readlen); retcode = MS_GENERROR; } else { retcode = MS_ENDOFFILE; } if ( msfp->recordcount == 0 ) { if ( verbose > 0 ) ms_log (2, "%s: No data records read, not SEED?\n", msfile); retcode = MS_NOTSEED; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -