You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1084 lines
31 KiB
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: 2014.197
***************************************************************************/
#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 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).
***************************************************************************/
int
msr_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 = 0;
uint16_t blkt_type;
uint16_t next_blkt;
uint32_t blkt_offset;
uint32_t blkt_length;
int blkt_count = 0;
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 and day */
if ( ! MS_ISVALIDYEARDAY (msr->fsdh->start_time.year, msr->fsdh->start_time.day) )
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 */
strncpy (sequence_number, msr->fsdh->sequence_number, 6);
sequence_number[6] = '\0';
msr->sequence_number = (int32_t) strtol (sequence_number, NULL, 10);
msr->dataquality = msr->fsdh->dataquality;
ms_strncpcleantail (msr->network, msr->fsdh->network, 2);
ms_strncpcleantail (msr->station, msr->fsdh->station, 5);
ms_strncpcleantail (msr->location, msr->fsdh->location, 2);
ms_strncpcleantail (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(): 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) &&
((int)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 ( (int)(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->blktoffset = blkt_offset - 4;
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->blktoffset = blkt_offset - 4;
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->blktoffset = blkt_offset - 4;
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->blktoffset = blkt_offset - 4;
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->blktoffset = blkt_offset - 4;
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->blktoffset = blkt_offset - 4;
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->blktoffset = blkt_offset - 4;
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->blktoffset = blkt_offset - 4;
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->blktoffset = blkt_offset - 4;
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->blktoffset = blkt_offset - 4;
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->blktoffset = blkt_offset - 4;
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->blktoffset = blkt_offset - 4;
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 )
{
ms_log (2, "msr_unpack(%s): Record length in Blockette 1000 (%d) != specified length (%d)\n",
UNPACK_SRCNAME, msr->reclen, reclen);
}
msr->encoding = blkt_1000->encoding;
msr->byteorder = blkt_1000->byteorder;
}
else if ( blkt_type == 1001 )
{ /* Found a Blockette 1001 */
blkt_link = msr_addblockette (msr, record + blkt_offset,
sizeof (struct blkt_1001_s),
blkt_type, 0);
if ( ! blkt_link )
break;
blkt_link->blktoffset = blkt_offset - 4;
blkt_link->next_blkt = next_blkt;
}
else if ( blkt_type == 2000 )
{ /* Found a Blockette 2000 */
struct blkt_2000_s *blkt_2000;
uint16_t b2klen;
/* Read the blockette length from blockette */
memcpy (&b2klen, record + blkt_offset, 2);
if ( headerswapflag ) ms_gswap2 (&b2klen);
/* Minus four bytes for the blockette type and next fields */
b2klen -= 4;
blkt_link = msr_addblockette (msr, record + blkt_offset,
b2klen, blkt_type, 0);
if ( ! blkt_link )
break;
blkt_link->blktoffset = blkt_offset - 4;
blkt_link->next_blkt = next_blkt;
blkt_2000 = (struct blkt_2000_s *) blkt_link->blktdata;
if ( headerswapflag )
{
ms_gswap2 (&blkt_2000->length);
ms_gswap2 (&blkt_2000->data_offset);
ms_gswap4 (&blkt_2000->recnum);
}
}
else
{ /* Unknown blockette type */
if ( blkt_length >= 4 )
{
blkt_link = msr_addblockette (msr, record + blkt_offset,
blkt_length - 4,
blkt_type, 0);
if ( ! blkt_link )
break;
blkt_link->blktoffset = blkt_offset - 4;
blkt_link->next_blkt = next_blkt;
}
}
/* Check that the next blockette offset is beyond the current blockette */
if ( next_blkt && next_blkt < (blkt_offset + blkt_length - 4) )
{
ms_log (2, "msr_unpack(%s): Offset to next blockette (%d) is within current blockette ending at byte %d\n",
UNPACK_SRCNAME, next_blkt, (blkt_offset + blkt_length - 4));
blkt_offset = 0;
}
/* Check that the offset is within record length */
else if ( next_blkt && next_blkt > reclen )
{
ms_log (2, "msr_unpack(%s): Offset to next blockette (%d) from type %d is beyond record length\n",
UNPACK_SRCNAME, next_blkt, blkt_type);
blkt_offset = 0;
}
else
{
blkt_offset = next_blkt;
}
blkt_count++;
} /* End of while looping through blockettes */
/* Check for a Blockette 1000 */
if ( msr->Blkt1000 == 0 )
{
if ( verbose > 1 )
{
ms_log (1, "%s: Warning: No Blockette 1000 found\n", UNPACK_SRCNAME);
}
}
/* Check that the data offset is after the blockette chain */
if ( blkt_link && msr->fsdh->numsamples && msr->fsdh->data_offset < (blkt_link->blktoffset + blkt_link->blktdatalen + 4) )
{
ms_log (1, "%s: Warning: Data offset in fixed header (%d) is within the blockette chain ending at %d\n",
UNPACK_SRCNAME, msr->fsdh->data_offset, (blkt_link->blktoffset + blkt_link->blktdatalen + 4));
}
/* Check that the blockette count matches the number parsed */
if ( msr->fsdh->numblockettes != blkt_count )
{
ms_log (1, "%s: Warning: Number of blockettes in fixed header (%d) does not match the number parsed (%d)\n",
UNPACK_SRCNAME, msr->fsdh->numblockettes, blkt_count);
}
/* Populate remaining common header fields */
msr->starttime = msr_starttime (msr);
msr->samprate = msr_samprate (msr);
/* Set MSRecord->byteorder if data byte order is forced */
if ( unpackdatabyteorder >= 0 )
{
msr->byteorder = unpackdatabyteorder;
}
/* Check if encoding format is forced */
if ( unpackencodingformat >= 0 )
{
msr->encoding = unpackencodingformat;
}
/* Use encoding format fallback if defined and no encoding is set,
* also make sure the byteorder is set by default to big endian */
if ( unpackencodingfallback >= 0 && msr->encoding == -1 )
{
msr->encoding = unpackencodingfallback;
if ( msr->byteorder == -1 )
{
msr->byteorder = 1;
}
}
/* Unpack the data samples if requested */
if ( dataflag && msr->samplecnt > 0 )
{
flag dswapflag = headerswapflag;
flag bigendianhost = ms_bigendianhost();
/* Determine byte order of the data and set the dswapflag as
needed; if no Blkt1000 or UNPACK_DATA_BYTEORDER environment
variable setting assume the order is the same as the header */
if ( msr->Blkt1000 != 0 && unpackdatabyteorder < 0 )
{
dswapflag = 0;
/* If BE host and LE data need swapping */
if ( bigendianhost && msr->byteorder == 0 )
dswapflag = 1;
/* If LE host and BE data (or bad byte order value) need swapping */
else if ( !bigendianhost && msr->byteorder > 0 )
dswapflag = 1;
}
else if ( unpackdatabyteorder >= 0 )
{
dswapflag = dataswapflag;
}
if ( verbose > 2 && dswapflag )
ms_log (1, "%s: Byte swapping needed for unpacking of data samples\n",
UNPACK_SRCNAME);
else if ( verbose > 2 )
ms_log (1, "%s: Byte swapping NOT needed for unpacking of data samples \n",
UNPACK_SRCNAME);
retval = msr_unpack_data (msr, dswapflag, verbose);
if ( retval < 0 )
return retval;
else
msr->numsamples = retval;
}
else
{
if ( msr->datasamples )
free (msr->datasamples);
msr->datasamples = 0;
msr->numsamples = 0;
}
/* Unset shared pointer to source name */
UNPACK_SRCNAME = NULL;
return MS_NOERROR;
} /* End of msr_unpack() */
/************************************************************************
* msr_unpack_data:
*
* Unpack Mini-SEED data samples for a given MSRecord. The packed
* data is accessed in the record indicated by MSRecord->record and
* the unpacked samples are placed in MSRecord->datasamples. The
* resulting data samples are either 32-bit integers, 32-bit floats
* or 64-bit floats in host byte order.
*
* Return number of samples unpacked or negative libmseed error code.
************************************************************************/
int
msr_unpack_data ( MSRecord *msr, int swapflag, flag verbose )
{
int datasize; /* byte size of data samples in record */
int nsamples; /* number of samples unpacked */
int unpacksize; /* byte size of unpacked samples */
int samplesize = 0; /* size of the data samples in bytes */
const char *dbuf;
int32_t *diffbuff;
int32_t x0, xn;
/* Sanity record length */
if ( msr->reclen == -1 )
{
ms_log (2, "msr_unpack_data(%s): Record size unknown\n",
UNPACK_SRCNAME);
return MS_NOTSEED;
}
else if ( msr->reclen < MINRECLEN || msr->reclen > MAXRECLEN )
{
ms_log (2, "msr_unpack_data(%s): Unsupported record length: %d\n",
UNPACK_SRCNAME, msr->reclen);
return MS_OUTOFRANGE;
}
/* Sanity check data offset before creating a pointer based on the value */
if ( msr->fsdh->data_offset < 48 || msr->fsdh->data_offset >= msr->reclen )
{
ms_log (2, "msr_unpack_data(%s): data offset value is not valid: %d\n",
UNPACK_SRCNAME, msr->fsdh->data_offset);
return MS_GENERROR;
}
datasize = msr->reclen - msr->fsdh->data_offset;
dbuf = msr->record + msr->fsdh->data_offset;
switch (msr->encoding)
{
case DE_ASCII:
samplesize = 1; break;
case DE_INT16:
case DE_INT32:
case DE_FLOAT32:
case DE_STEIM1:
case DE_STEIM2:
case DE_GEOSCOPE24:
case DE_GEOSCOPE163:
case DE_GEOSCOPE164:
case DE_CDSN:
case DE_SRO:
case DE_DWWSSN:
samplesize = 4; break;
case DE_FLOAT64:
samplesize = 8; break;
default:
samplesize = 0; break;
}
/* Calculate buffer size needed for unpacked samples */
unpacksize = (int) msr->samplecnt * samplesize;
/* (Re)Allocate space for the unpacked data */
if ( unpacksize > 0 )
{
msr->datasamples = realloc (msr->datasamples, unpacksize);
if ( msr->datasamples == NULL )
{
ms_log (2, "msr_unpack_data(%s): Cannot (re)allocate memory\n",
UNPACK_SRCNAME);
return MS_GENERROR;
}
}
else
{
if ( msr->datasamples )
free (msr->datasamples);
msr->datasamples = 0;
msr->numsamples = 0;
}
if ( verbose > 2 )
ms_log (1, "%s: Unpacking %lld samples\n",
UNPACK_SRCNAME, (long long int)msr->samplecnt);
/* Decide if this is a encoding that we can decode */
switch (msr->encoding)
{
case DE_ASCII:
if ( verbose > 1 )
ms_log (1, "%s: Found ASCII data\n", UNPACK_SRCNAME);
nsamples = (int)msr->samplecnt;
memcpy (msr->datasamples, dbuf, nsamples);
msr->sampletype = 'a';
break;
case DE_INT16:
if ( verbose > 1 )
ms_log (1, "%s: Unpacking INT-16 data samples\n", UNPACK_SRCNAME);
nsamples = msr_unpack_int_16 ((int16_t *)dbuf, (int)msr->samplecnt,
(int)msr->samplecnt, msr->datasamples,
swapflag);
msr->sampletype = 'i';
break;
case DE_INT32:
if ( verbose > 1 )
ms_log (1, "%s: Unpacking INT-32 data samples\n", UNPACK_SRCNAME);
nsamples = msr_unpack_int_32 ((int32_t *)dbuf, (int)msr->samplecnt,
(int)msr->samplecnt, msr->datasamples,
swapflag);
msr->sampletype = 'i';
break;
case DE_FLOAT32:
if ( verbose > 1 )
ms_log (1, "%s: Unpacking FLOAT-32 data samples\n", UNPACK_SRCNAME);
nsamples = msr_unpack_float_32 ((float *)dbuf, (int)msr->samplecnt,
(int)msr->samplecnt, msr->datasamples,
swapflag);
msr->sampletype = 'f';
break;
case DE_FLOAT64:
if ( verbose > 1 )
ms_log (1, "%s: Unpacking FLOAT-64 data samples\n", UNPACK_SRCNAME);
nsamples = msr_unpack_float_64 ((double *)dbuf, (int)msr->samplecnt,
(int)msr->samplecnt, msr->datasamples,
swapflag);
msr->sampletype = 'd';
break;
case DE_STEIM1:
diffbuff = (int32_t *) malloc(unpacksize);
if ( diffbuff == NULL )
{
ms_log (2, "msr_unpack_data(%s): Cannot allocate diff buffer\n",
UNPACK_SRCNAME);
return MS_GENERROR;
}
if ( verbose > 1 )
ms_log (1, "%s: Unpacking Steim-1 data frames\n", UNPACK_SRCNAME);
nsamples = msr_unpack_steim1 ((FRAME *)dbuf, datasize, (int)msr->samplecnt,
(int)msr->samplecnt, msr->datasamples, diffbuff,
&x0, &xn, swapflag, verbose);
msr->sampletype = 'i';
free (diffbuff);
break;
case DE_STEIM2:
diffbuff = (int32_t *) malloc(unpacksize);
if ( diffbuff == NULL )
{
ms_log (2, "msr_unpack_data(%s): Cannot allocate diff buffer\n",
UNPACK_SRCNAME);
return MS_GENERROR;
}
if ( verbose > 1 )
ms_log (1, "%s: Unpacking Steim-2 data frames\n", UNPACK_SRCNAME);
nsamples = msr_unpack_steim2 ((FRAME *)dbuf, datasize, (int)msr->samplecnt,
(int)msr->samplecnt, msr->datasamples, diffbuff,
&x0, &xn, swapflag, verbose);
msr->sampletype = 'i';
free (diffbuff);
break;
case DE_GEOSCOPE24:
case DE_GEOSCOPE163:
case DE_GEOSCOPE164:
if ( verbose > 1 )
{
if ( msr->encoding == DE_GEOSCOPE24 )
ms_log (1, "%s: Unpacking GEOSCOPE 24bit integer data samples\n",
UNPACK_SRCNAME);
if ( msr->encoding == DE_GEOSCOPE163 )
ms_log (1, "%s: Unpacking GEOSCOPE 16bit gain ranged/3bit exponent data samples\n",
UNPACK_SRCNAME);
if ( msr->encoding == DE_GEOSCOPE164 )
ms_log (1, "%s: Unpacking GEOSCOPE 16bit gain ranged/4bit exponent data samples\n",
UNPACK_SRCNAME);
}
nsamples = msr_unpack_geoscope (dbuf, (int)msr->samplecnt, (int)msr->samplecnt,
msr->datasamples, msr->encoding, swapflag);
msr->sampletype = 'f';
break;
case DE_CDSN:
if ( verbose > 1 )
ms_log (1, "%s: Unpacking CDSN encoded data samples\n", UNPACK_SRCNAME);
nsamples = msr_unpack_cdsn ((int16_t *)dbuf, (int)msr->samplecnt, (int)msr->samplecnt,
msr->datasamples, swapflag);
msr->sampletype = 'i';
break;
case DE_SRO:
if ( verbose > 1 )
ms_log (1, "%s: Unpacking SRO encoded data samples\n", UNPACK_SRCNAME);
nsamples = msr_unpack_sro ((int16_t *)dbuf, (int)msr->samplecnt, (int)msr->samplecnt,
msr->datasamples, swapflag);
msr->sampletype = 'i';
break;
case DE_DWWSSN:
if ( verbose > 1 )
ms_log (1, "%s: Unpacking DWWSSN encoded data samples\n", UNPACK_SRCNAME);
nsamples = msr_unpack_dwwssn ((int16_t *)dbuf, (int)msr->samplecnt, (int)msr->samplecnt,
msr->datasamples, swapflag);
msr->sampletype = 'i';
break;
default:
ms_log (2, "%s: Unsupported encoding format %d (%s)\n",
UNPACK_SRCNAME, msr->encoding, (char *) ms_encodingstr(msr->encoding));
return MS_UNKNOWNFORMAT;
}
return nsamples;
} /* End of msr_unpack_data() */
/************************************************************************
* check_environment:
*
* Check environment variables and set global variables appropriately.
*
* Return 0 on success and -1 on error.
************************************************************************/
static int
check_environment (int verbose)
{
char *envvariable;
/* Read possible environmental variables that force byteorder */
if ( unpackheaderbyteorder == -2 )
{
if ( (envvariable = getenv("UNPACK_HEADER_BYTEORDER")) )
{
if ( *envvariable != '0' && *envvariable != '1' )
{
ms_log (2, "Environment variable UNPACK_HEADER_BYTEORDER must be set to '0' or '1'\n");
return -1;
}
else if ( *envvariable == '0' )
{
unpackheaderbyteorder = 0;
if ( verbose > 2 )
ms_log (1, "UNPACK_HEADER_BYTEORDER=0, unpacking little-endian header\n");
}
else
{
unpackheaderbyteorder = 1;
if ( verbose > 2 )
ms_log (1, "UNPACK_HEADER_BYTEORDER=1, unpacking big-endian header\n");
}
}
else
{
unpackheaderbyteorder = -1;
}
}
if ( unpackdatabyteorder == -2 )
{
if ( (envvariable = getenv("UNPACK_DATA_BYTEORDER")) )
{
if ( *envvariable != '0' && *envvariable != '1' )
{
ms_log (2, "Environment variable UNPACK_DATA_BYTEORDER must be set to '0' or '1'\n");
return -1;
}
else if ( *envvariable == '0' )
{
unpackdatabyteorder = 0;
if ( verbose > 2 )
ms_log (1, "UNPACK_DATA_BYTEORDER=0, unpacking little-endian data samples\n");
}
else
{
unpackdatabyteorder = 1;
if ( verbose > 2 )
ms_log (1, "UNPACK_DATA_BYTEORDER=1, unpacking big-endian data samples\n");
}
}
else
{
unpackdatabyteorder = -1;
}
}
/* Read possible environmental variable that forces encoding format */
if ( unpackencodingformat == -2 )
{
if ( (envvariable = getenv("UNPACK_DATA_FORMAT")) )
{
unpackencodingformat = (int) strtol (envvariable, NULL, 10);
if ( unpackencodingformat < 0 || unpackencodingformat > 33 )
{
ms_log (2, "Environment variable UNPACK_DATA_FORMAT set to invalid value: '%d'\n", unpackencodingformat);
return -1;
}
else if ( verbose > 2 )
ms_log (1, "UNPACK_DATA_FORMAT, unpacking data in encoding format %d\n", unpackencodingformat);
}
else
{
unpackencodingformat = -1;
}
}
/* Read possible environmental variable to be used as a fallback encoding format */
if ( unpackencodingfallback == -2 )
{
if ( (envvariable = getenv("UNPACK_DATA_FORMAT_FALLBACK")) )
{
unpackencodingfallback = (int) strtol (envvariable, NULL, 10);
if ( unpackencodingfallback < 0 || unpackencodingfallback > 33 )
{
ms_log (2, "Environment variable UNPACK_DATA_FORMAT_FALLBACK set to invalid value: '%d'\n",
unpackencodingfallback);
return -1;
}
else if ( verbose > 2 )
ms_log (1, "UNPACK_DATA_FORMAT_FALLBACK, fallback data unpacking encoding format %d\n",
unpackencodingfallback);
}
else
{
unpackencodingfallback = 10; /* Default fallback is Steim-1 encoding */
}
}
return 0;
} /* End of check_environment() */