📄 unpack.c
字号:
/*************************************************************************** * unpack.c: * * Generic routines to unpack Mini-SEED records. * * Appropriate values from the record header will be byte-swapped to * the host order. The purpose of this code is to provide a portable * way of accessing common SEED data record header information. All * data structures in SEED 2.4 data records are supported. The data * samples are optionally decompressed/unpacked. * * Written by Chad Trabant, * ORFEUS/EC-Project MEREDIAN * IRIS Data Management Center * * modified: 2007.178 ***************************************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <ctype.h>#include "libmseed.h"#include "unpackdata.h"/* Function(s) internal to this file */static int msr_unpack_data (MSRecord * msr, int swapflag, int verbose);static int check_environment (int verbose);/* Header and data byte order flags controlled by environment variables *//* -2 = not checked, -1 = checked but not set, or 0 = LE and 1 = BE */flag unpackheaderbyteorder = -2;flag unpackdatabyteorder = -2;/* Data encoding format/fallback controlled by environment variable *//* -2 = not checked, -1 = checked but not set, or = encoding */int unpackencodingformat = -2;int unpackencodingfallback = -2;/* A pointer to the srcname of the record being unpacked */char *UNPACK_SRCNAME = NULL;/*************************************************************************** * msr_unpack: * * Unpack a SEED data record header/blockettes and populate a MSRecord * struct. All approriate fields are byteswapped, if needed, and * pointers to structured data are setup in addition to setting the * common header fields. * * If 'dataflag' is true the data samples are unpacked/decompressed * and the MSRecord->datasamples pointer is set appropriately. The * data samples will be either 32-bit integers, 32-bit floats or * 64-bit floats (doubles) with the same byte order as the host * machine. The MSRecord->numsamples will be set to the actual number * of samples unpacked/decompressed and MSRecord->sampletype will * indicated the sample type. * * All appropriate values will be byte-swapped to the host order, * including the data samples. * * All header values, blockette values and data samples will be * overwritten by subsequent calls to this function. * * If the msr struct is NULL it will be allocated. * * Returns MS_NOERROR and populates the MSRecord struct at *ppmsr on * success, otherwise returns a libmseed error code (listed in * libmseed.h). ***************************************************************************/intmsr_unpack ( char *record, int reclen, MSRecord **ppmsr, flag dataflag, flag verbose ){ flag headerswapflag = 0; flag dataswapflag = 0; int retval; MSRecord *msr = NULL; char sequence_number[7]; char srcname[50]; /* For blockette parsing */ BlktLink *blkt_link; uint16_t blkt_type; uint16_t next_blkt; uint32_t blkt_offset; uint32_t blkt_length; if ( ! ppmsr ) { ms_log (2, "msr_unpack(): ppmsr argument cannot be NULL\n"); return MS_GENERROR; } /* Verify that record includes a valid header */ if ( ! MS_ISVALIDHEADER(record) ) { ms_recsrcname (record, srcname, 1); ms_log (2, "msr_unpack(%s) Record header & quality indicator unrecognized: '%c'\n", srcname); ms_log (2, "msr_unpack(%s) This is not a valid Mini-SEED record\n", srcname); return MS_NOTSEED; } /* Verify that passed record length is within supported range */ if ( reclen < MINRECLEN || reclen > MAXRECLEN ) { ms_recsrcname (record, srcname, 1); ms_log (2, "msr_unpack(%s): Record length is out of range: %d\n", srcname, reclen); return MS_OUTOFRANGE; } /* Initialize the MSRecord */ if ( ! (*ppmsr = msr_init (*ppmsr)) ) return MS_GENERROR; /* Shortcut pointer, historical and help readability */ msr = *ppmsr; /* Set raw record pointer and record length */ msr->record = record; msr->reclen = reclen; /* Check environment variables if necessary */ if ( unpackheaderbyteorder == -2 || unpackdatabyteorder == -2 || unpackencodingformat == -2 || unpackencodingfallback == -2 ) if ( check_environment(verbose) ) return MS_GENERROR; /* Allocate and copy fixed section of data header */ msr->fsdh = realloc (msr->fsdh, sizeof (struct fsdh_s)); if ( msr->fsdh == NULL ) { ms_log (2, "msr_unpack(): Cannot allocate memory\n"); return MS_GENERROR; } memcpy (msr->fsdh, record, sizeof (struct fsdh_s)); /* Check to see if byte swapping is needed by testing the year */ if ( (msr->fsdh->start_time.year < 1920) || (msr->fsdh->start_time.year > 2020) ) headerswapflag = dataswapflag = 1; /* Check if byte order is forced */ if ( unpackheaderbyteorder >= 0 ) { headerswapflag = ( ms_bigendianhost() != unpackheaderbyteorder ) ? 1 : 0; } if ( unpackdatabyteorder >= 0 ) { dataswapflag = ( ms_bigendianhost() != unpackdatabyteorder ) ? 1 : 0; } /* Swap byte order? */ if ( headerswapflag ) { MS_SWAPBTIME (&msr->fsdh->start_time); ms_gswap2a (&msr->fsdh->numsamples); ms_gswap2a (&msr->fsdh->samprate_fact); ms_gswap2a (&msr->fsdh->samprate_mult); ms_gswap4a (&msr->fsdh->time_correct); ms_gswap2a (&msr->fsdh->data_offset); ms_gswap2a (&msr->fsdh->blockette_offset); } /* Populate some of the common header fields */ ms_strncpclean (sequence_number, msr->fsdh->sequence_number, 6); msr->sequence_number = (int32_t) strtol (sequence_number, NULL, 10); msr->dataquality = msr->fsdh->dataquality; ms_strncpclean (msr->network, msr->fsdh->network, 2); ms_strncpclean (msr->station, msr->fsdh->station, 5); ms_strncpclean (msr->location, msr->fsdh->location, 2); ms_strncpclean (msr->channel, msr->fsdh->channel, 3); msr->samplecnt = msr->fsdh->numsamples; /* Generate source name for MSRecord */ if ( msr_srcname (msr, srcname, 1) == NULL ) { ms_log (2, "msr_unpack_data(): Cannot generate srcname\n"); return MS_GENERROR; } /* Set shared srcname pointer to source name */ UNPACK_SRCNAME = &srcname[0]; /* Report byte swapping status */ if ( verbose > 2 ) { if ( headerswapflag ) ms_log (1, "%s: Byte swapping needed for unpacking of header\n", UNPACK_SRCNAME); else ms_log (1, "%s: Byte swapping NOT needed for unpacking of header\n", UNPACK_SRCNAME); } /* Traverse the blockettes */ blkt_offset = msr->fsdh->blockette_offset; while ((blkt_offset != 0) && (blkt_offset < reclen) && (blkt_offset < MAXRECLEN)) { /* Every blockette has a similar 4 byte header: type and next */ memcpy (&blkt_type, record + blkt_offset, 2); blkt_offset += 2; memcpy (&next_blkt, record + blkt_offset, 2); blkt_offset += 2; if ( headerswapflag ) { ms_gswap2 (&blkt_type); ms_gswap2 (&next_blkt); } /* Get blockette length */ blkt_length = ms_blktlen (blkt_type, record + blkt_offset - 4, headerswapflag); if ( blkt_length == 0 ) { ms_log (2, "msr_unpack(%s): Unknown blockette length for type %d\n", UNPACK_SRCNAME, blkt_type); break; } /* Make sure blockette is contained within the msrecord buffer */ if ( (blkt_offset - 4 + blkt_length) > reclen ) { ms_log (2, "msr_unpack(%s): Blockette %d extends beyond record size, truncated?\n", UNPACK_SRCNAME, blkt_type); break; } if ( blkt_type == 100 ) { /* Found a Blockette 100 */ struct blkt_100_s *blkt_100; blkt_link = msr_addblockette (msr, record + blkt_offset, sizeof (struct blkt_100_s), blkt_type, 0); if ( ! blkt_link ) break; blkt_link->next_blkt = next_blkt; blkt_100 = (struct blkt_100_s *) blkt_link->blktdata; if ( headerswapflag ) { ms_gswap4 (&blkt_100->samprate); } msr->samprate = msr->Blkt100->samprate; } else if ( blkt_type == 200 ) { /* Found a Blockette 200 */ struct blkt_200_s *blkt_200; blkt_link = msr_addblockette (msr, record + blkt_offset, sizeof (struct blkt_200_s), blkt_type, 0); if ( ! blkt_link ) break; blkt_link->next_blkt = next_blkt; blkt_200 = (struct blkt_200_s *) blkt_link->blktdata; if ( headerswapflag ) { ms_gswap4 (&blkt_200->amplitude); ms_gswap4 (&blkt_200->period); ms_gswap4 (&blkt_200->background_estimate); MS_SWAPBTIME (&blkt_200->time); } } else if ( blkt_type == 201 ) { /* Found a Blockette 201 */ struct blkt_201_s *blkt_201; blkt_link = msr_addblockette (msr, record + blkt_offset, sizeof (struct blkt_201_s), blkt_type, 0); if ( ! blkt_link ) break; blkt_link->next_blkt = next_blkt; blkt_201 = (struct blkt_201_s *) blkt_link->blktdata; if ( headerswapflag ) { ms_gswap4 (&blkt_201->amplitude); ms_gswap4 (&blkt_201->period); ms_gswap4 (&blkt_201->background_estimate); MS_SWAPBTIME (&blkt_201->time); } } else if ( blkt_type == 300 ) { /* Found a Blockette 300 */ struct blkt_300_s *blkt_300; blkt_link = msr_addblockette (msr, record + blkt_offset, sizeof (struct blkt_300_s), blkt_type, 0); if ( ! blkt_link ) break; blkt_link->next_blkt = next_blkt; blkt_300 = (struct blkt_300_s *) blkt_link->blktdata; if ( headerswapflag ) { MS_SWAPBTIME (&blkt_300->time); ms_gswap4 (&blkt_300->step_duration); ms_gswap4 (&blkt_300->interval_duration); ms_gswap4 (&blkt_300->amplitude); ms_gswap4 (&blkt_300->reference_amplitude); } } else if ( blkt_type == 310 ) { /* Found a Blockette 310 */ struct blkt_310_s *blkt_310; blkt_link = msr_addblockette (msr, record + blkt_offset, sizeof (struct blkt_310_s), blkt_type, 0); if ( ! blkt_link ) break; blkt_link->next_blkt = next_blkt; blkt_310 = (struct blkt_310_s *) blkt_link->blktdata; if ( headerswapflag ) { MS_SWAPBTIME (&blkt_310->time); ms_gswap4 (&blkt_310->duration); ms_gswap4 (&blkt_310->period); ms_gswap4 (&blkt_310->amplitude); ms_gswap4 (&blkt_310->reference_amplitude); } } else if ( blkt_type == 320 ) { /* Found a Blockette 320 */ struct blkt_320_s *blkt_320; blkt_link = msr_addblockette (msr, record + blkt_offset, sizeof (struct blkt_320_s), blkt_type, 0); if ( ! blkt_link ) break; blkt_link->next_blkt = next_blkt; blkt_320 = (struct blkt_320_s *) blkt_link->blktdata; if ( headerswapflag ) { MS_SWAPBTIME (&blkt_320->time); ms_gswap4 (&blkt_320->duration); ms_gswap4 (&blkt_320->ptp_amplitude); ms_gswap4 (&blkt_320->reference_amplitude); } } else if ( blkt_type == 390 ) { /* Found a Blockette 390 */ struct blkt_390_s *blkt_390; blkt_link = msr_addblockette (msr, record + blkt_offset, sizeof (struct blkt_390_s), blkt_type, 0); if ( ! blkt_link ) break; blkt_link->next_blkt = next_blkt; blkt_390 = (struct blkt_390_s *) blkt_link->blktdata; if ( headerswapflag ) { MS_SWAPBTIME (&blkt_390->time); ms_gswap4 (&blkt_390->duration); ms_gswap4 (&blkt_390->amplitude); } } else if ( blkt_type == 395 ) { /* Found a Blockette 395 */ struct blkt_395_s *blkt_395; blkt_link = msr_addblockette (msr, record + blkt_offset, sizeof (struct blkt_395_s), blkt_type, 0); if ( ! blkt_link ) break; blkt_link->next_blkt = next_blkt; blkt_395 = (struct blkt_395_s *) blkt_link->blktdata; if ( headerswapflag ) { MS_SWAPBTIME (&blkt_395->time); } } else if ( blkt_type == 400 ) { /* Found a Blockette 400 */ struct blkt_400_s *blkt_400; blkt_link = msr_addblockette (msr, record + blkt_offset, sizeof (struct blkt_400_s), blkt_type, 0); if ( ! blkt_link ) break; blkt_link->next_blkt = next_blkt; blkt_400 = (struct blkt_400_s *) blkt_link->blktdata; if ( headerswapflag ) { ms_gswap4 (&blkt_400->azimuth); ms_gswap4 (&blkt_400->slowness); ms_gswap2 (&blkt_400->configuration); } } else if ( blkt_type == 405 ) { /* Found a Blockette 405 */ struct blkt_405_s *blkt_405; blkt_link = msr_addblockette (msr, record + blkt_offset, sizeof (struct blkt_405_s), blkt_type, 0); if ( ! blkt_link ) break; blkt_link->next_blkt = next_blkt; blkt_405 = (struct blkt_405_s *) blkt_link->blktdata; if ( headerswapflag ) { ms_gswap2 (&blkt_405->delay_values); } if ( verbose > 0 ) { ms_log (1, "msr_unpack(%s): WARNING Blockette 405 cannot be fully supported\n", UNPACK_SRCNAME); } } else if ( blkt_type == 500 ) { /* Found a Blockette 500 */ struct blkt_500_s *blkt_500; blkt_link = msr_addblockette (msr, record + blkt_offset, sizeof (struct blkt_500_s), blkt_type, 0); if ( ! blkt_link ) break; blkt_link->next_blkt = next_blkt; blkt_500 = (struct blkt_500_s *) blkt_link->blktdata; if ( headerswapflag ) { ms_gswap4 (&blkt_500->vco_correction); MS_SWAPBTIME (&blkt_500->time); ms_gswap4 (&blkt_500->exception_count); } } else if ( blkt_type == 1000 ) { /* Found a Blockette 1000 */ struct blkt_1000_s *blkt_1000; blkt_link = msr_addblockette (msr, record + blkt_offset, sizeof (struct blkt_1000_s), blkt_type, 0); if ( ! blkt_link ) break; blkt_link->next_blkt = next_blkt; blkt_1000 = (struct blkt_1000_s *) blkt_link->blktdata; /* Calculate record length in bytes as 2^(blkt_1000->reclen) */ msr->reclen = (uint32_t) 1 << blkt_1000->reclen; /* Compare against the specified length */ if ( msr->reclen != reclen && verbose )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -