INT_TIME decode_time_sdr
   (SDR_TIME	st,		/* SDR_TIME structure to decode.	*/
    int		wordorder)	/* wordorder of time contents.		*/
{
    SDR_TIME ct = st;
    EXT_TIME et;

    if (my_wordorder < 0) get_my_wordorder();
    if (my_wordorder != wordorder) {
	swab2 ((short int *)&ct.year);
	swab2 ((short int *)&ct.day);
	swab2 ((short int *)&ct.ticks);
    }
#ifdef	QLIB_DEBUG
    if (debug_option & 128) 
    fprintf (info, "time = %02d.%02d %02d:%02d:%02d:%04d\n",
	     ct.year,	ct.day,	    ct.hour,
	     ct.minute,	ct.second,  ct.ticks);
#endif
    et.year = ct.year;
    et.doy = ct.day;
    et.hour = ct.hour;
    et.minute = ct.minute;
    et.second = ct.second;
    et.usec = ct.ticks * USECS_PER_TICK;
    dy_to_mdy (et.doy, et.year, &et.month, &et.day);
    return (normalize_time(ext_to_int(et)));
}
DATA_HDR *new_data_hdr ()
{
    DATA_HDR	    *hdr;

    if (my_wordorder < 0) get_my_wordorder();
    hdr = (DATA_HDR *) malloc (sizeof(DATA_HDR));
    if (hdr == NULL) {
	fprintf (stderr, "Error: unable to allocate data_hdr for output\n");
	fflush (stderr);
	if (QLIB2_CLASSIC) exit (1);
	return (NULL);
    }
    init_data_hdr (hdr);
    return (hdr);
}
char *asc_sdr_time
   (char	*str,		/* string to encode time into.		*/
    SDR_TIME	st,		/* SDR_TIME structure to decode.	*/
    int		wordorder)	/* wordorder for encoded time contents.	*/

{
    if (my_wordorder < 0) get_my_wordorder();
    if (my_wordorder != wordorder) {
	swab2 ((short int *)&st.year);
	swab2 ((short int *)&st.day);
	swab2 ((short int *)&st.ticks);
    }
    sprintf(str,"%04d,%03d,%02d:%02d:%02d.%04d", st.year,
	    st.day, st.hour, st.minute, st.second, st.ticks);
    return (str);
}
int wordorder_from_time
   (unsigned char *p)		/* ptr to fixed data time field.	*/
{
    int wordorder;
    unsigned char *cyear = p;
    /* This check ONLY works for dates in the range [1800, ..., 2054].	*/
    if (my_wordorder < 0) get_my_wordorder();
    if      ((cyear[0] == 0x07 && cyear[1] >= 0x08) ||
	     (cyear[0] == 0x08 && cyear[1] <  0x07)) wordorder = SEED_BIG_ENDIAN;
    else if ((cyear[1] == 0x07 && cyear[0] >= 0x08) ||
	     (cyear[1] == 0x08 && cyear[0] <  0x07)) wordorder = SEED_LITTLE_ENDIAN;
    else {
	fprintf (stderr, "Error: Unable to determine wordorder from time\n");
	fflush (stderr);
	if (QLIB2_CLASSIC) exit(1);
	return (MS_ERROR);
    }
    return (wordorder);
}
int blockettecmp
   (BS		*bs1,		/* BS* of first blockette to compare.	*/
    BS		*bs2)		/* BS* of first blockette to compare.	*/
{
    int swapflag;
    SEED_UWORD l1, l2, type1, type2;
    int status;
    char *pbc1, *pbc2;
    char *p = NULL;

    if (my_wordorder < 0) get_my_wordorder();
    if (bs1 == NULL && bs2 == NULL) return (0);
    if (bs1 == NULL) return (-1);
    if (bs2 == NULL) return (1);
    swapflag = (bs1->wordorder != bs2->wordorder);
    type1 = bs1->type;
    type2 = bs2->type;
    if (swapflag && bs1->wordorder != my_wordorder) swab2 ((short int *)&type1);
    if (swapflag && bs2->wordorder != my_wordorder) swab2 ((short int *)&type2);
    if (type1-type2) return (type1-type2);
    l1 = bs1->len;
    l2 = bs2->len;
    if (l1-l2) return (l1-l2);
    pbc1 = (char *)bs1->pb;
    pbc2 = (char *)bs2->pb;
    if (swapflag) {
	/* Reorder the wordorder of one of the blockettes for compare.	*/
	p = (char *)malloc(l1-4);
	if (bs1->wordorder != my_wordorder) {
	    memcpy (p, pbc1, l1);
	    swab_blockette (type1, pbc1, l1);
	    pbc1 = p;
	}
	else {
	    memcpy (p, pbc2, l2);
	    swab_blockette (type2, pbc2, l2);
	    pbc2 = p;
	}
    }
    status = memcmp(pbc1+4, pbc2+4, l1-4);
    if (swapflag && p) free (p);
    return (status);
}
int write_blockettes
   (DATA_HDR	*hdr,		/* ptr to data_hdr			*/
    char	*str)		/* ptr to output SDR.			*/
{
    BS *bs = hdr->pblockettes;
    int offset = hdr->first_blockette;
    SEED_UWORD next;
    int alen;
    int swapflag;

    if (my_wordorder < 0) get_my_wordorder();
    /* Ensure initial offset is a multiple of 4.			*/
    if (offset%4) {
	memset (str+offset, 0, 4-(offset%4));
	offset += 4-(offset%4);
	((SDR_HDR *)str)->first_blockette = offset;
    }
    while (bs != (BS *)NULL) {
	/* Ensure offset to next blockette is correct.			*/
	alen = bs->len;
	if (bs->len%4) alen += 4-(bs->len%4);
	next = (bs->next == NULL) ? 0 : offset + alen;
	if (my_wordorder != bs->wordorder) swab2((short int *)&next);
	((BLOCKETTE_HDR *)(bs->pb))->next = next;
	memcpy (str+offset,bs->pb,bs->len);
	if (alen != bs->len) memset(str+offset+bs->len, 0, alen-bs->len);
	/* Ensure blockette wordorder is the same as hdr wordorder.	*/
	swapflag = (hdr->hdr_wordorder != bs->wordorder);
	if (swapflag) {
	    swab_blockette (bs->type, str+offset, bs->len);
	}
	offset += alen;
	bs = bs->next;
    }
    if (hdr->first_data > 0 && offset > hdr->first_data) {
	fprintf (stderr, "Error: blockettes won't fit between hdr and data.\n");
	fflush (stderr);
	if (QLIB2_CLASSIC) exit(1);
	return (MS_ERROR);
    }
    return (0);
}
int update_sdr_hdr
   (SDR_HDR	*sh,		/* ptr to space for SDR data hdr.	*/
    DATA_HDR	*hdr)		/* initial DATA_HDR for SDR record.	*/
{
    int swapflag;		/* flag to indicate byteswapping.	*/
    short int stmp;

    if (my_wordorder < 0) get_my_wordorder();
    swapflag = (my_wordorder != hdr->hdr_wordorder);
    if (swapflag) {
	stmp = hdr->num_samples;
	swab2 (&stmp);
	sh->num_samples = stmp;
    }
    else {
	sh->num_samples = hdr->num_samples;
    }
    if (hdr->num_samples == 0) sh->first_data = 0;
    return (0);
}
int add_required_miniseed_blockettes 
   (DATA_HDR	*hdr)		/* ptr to DATA_HDR.			*/
{
    int status = 0;
    /* Currently only blockette 1000 is required for miniSEED.		*/
    if (my_wordorder < 0) get_my_wordorder();
    if (find_blockette(hdr, 1000) == NULL) {
	BLOCKETTE_1000 b1000;
	int ok;
	b1000.hdr.type = 1000;
	b1000.hdr.next = 0;
	b1000.format = hdr->data_type;
	b1000.word_order = SEED_BIG_ENDIAN;
	b1000.data_rec_len = roundoff(log2((double)hdr->blksize));
	b1000.reserved = 0;
	ok = add_blockette (hdr, (char *)&b1000, 1000, sizeof(BLOCKETTE_1000),
			    my_wordorder, 0);
	if (! ok) status = MS_ERROR;
    }
    return (status);
}
time_t unix_time_from_sdr_time
   (SDR_TIME	st,		/* SDR_TIME structure to convert.	*/
    int		wordorder)	/* wordorder for encoded time contents.	*/
    
{    
    EXT_TIME	et;

    if (my_wordorder < 0) get_my_wordorder();
    if (my_wordorder != wordorder) {
	swab2 ((short int *)&st.year);
	swab2 ((short int *)&st.day);
	swab2 ((short int *)&st.ticks);
    }
    et.year = st.year;
    et.doy = st.day;
    et.hour = st.hour;
    et.minute = st.minute;
    et.second = st.second;
    et.usec = st.ticks * USECS_PER_TICK;
    dy_to_mdy (et.doy, et.year, &et.month, &et.day);
    return (unix_time_from_ext_time(et));
}
SDR_TIME encode_time_sdr
   (INT_TIME	it,		/* IN_TIME structure to decode.		*/
    int		wordorder)	/* wordorder for encoded time contents.	*/
{
    SDR_TIME st;
    EXT_TIME et = int_to_ext(it);

    if (my_wordorder < 0) get_my_wordorder();
    st.year = et.year;
    st.day = et.doy;
    st.hour = et.hour;
    st.minute = et.minute;
    st.second = et.second;
    st.pad = 0;
    st.ticks = et.usec / USECS_PER_TICK;
    if (my_wordorder != wordorder) {
	swab2 ((short int *)&st.year);
	swab2 ((short int *)&st.day);
	swab2 ((short int *)&st.ticks);
    }
    return (st);
}
int delete_blockette 
   (DATA_HDR	*hdr,		/* ptr to DATA_HDR.			*/
    int		n)		/* blockette # to delete.  -1 -> ALL.	*/
{
    BS *bs = hdr->pblockettes;
    BS *pbs = (BS *)NULL;
    BS *dbs;
    int num_deleted = 0;
    SEED_UWORD type;

    /*	Don't worry about updating the offset within the blockette	*/
    /*	headers, since we will do that on output.			*/
    if (my_wordorder < 0) get_my_wordorder();
    while (bs != (BS *)NULL) {
	type = bs->type;
	if ( n < 0 || n == type) {
	    if (pbs == NULL)
		hdr->pblockettes = bs->next;
	    else 
		pbs->next = bs->next;
	    --(hdr->num_blockettes);
	    if (hdr->num_blockettes <= 0) 
		hdr->first_blockette = 0;
	    dbs = bs;
	    bs = bs->next;
	    free (dbs->pb);
	    free ((char *)dbs);
	    ++num_deleted;
	}
	else {
	    pbs = bs;
	    bs = bs->next;
	}
    }
    return (num_deleted);
}
Example #12
0
int pack_steim2
   (SDF		*p_sdf,		/* ptr to SDR structure.		*/
    int		data[],		/* unpacked data array.			*/
    int		diff[],		/* unpacked diff array.			*/
    int		ns,		/* num_samples.				*/
    int		nf,		/* total number of data frames.		*/
    int		pad,		/* flag to specify padding to nf.  	*/
    int		data_wordorder,	/* wordorder of data (NOT USED).	*/
    int		*pnframes,	/* number of frames actually packed.	*/
    int		*pnsamples)	/* number of samples actually packed.	*/
{
    int		points_remaining = ns;
    int		*minbits;	/* min bits for difference.		*/
    int		i, j;
    int		mask;
    int		ipt = 0;	/* index of initial data to pack.	*/
    int		fn = 0;		/* index of initial frame to pack.	*/
    int		wn = 2;		/* index of initial word to pack.	*/
    int		itmp;
    short int	stmp;
    int		swapflag;
    int		nb;		/* number of minbits to compute.	*/
    int		max_samples_per_frame;

    if (my_wordorder < 0) get_my_wordorder();
    swapflag = (my_wordorder != data_wordorder);

    max_samples_per_frame = 8 * VALS_PER_FRAME;	/* steim2 compression.	*/
    nb = max_samples_per_frame * nf;
    if (nb > points_remaining) nb = points_remaining;

    minbits = NULL;
    minbits = (int *)malloc(nb * sizeof(int));
    if (minbits == NULL) {
	fprintf (stderr, "Error: mallocing minbits in pack_steim1\n");
	fflush (stderr);
	if (QLIB2_CLASSIC) exit(1);
	return (MS_ERROR);
    }
    for (i=0; i<nb; i++) MINBITS(diff[i],minbits[i]);
    
    p_sdf->f[fn].ctrl = 0;

    /*	Set new X0 value in first frame.				*/
    X0 = data[0];
    if (swapflag) swab4((int *)&X0);
    p_sdf->f[fn].ctrl = (p_sdf->f[fn].ctrl<<2) | STEIM2_SPECIAL_MASK;
    XN = data[ns-1];
    if (swapflag) swab4((int *)&XN);
    p_sdf->f[fn].ctrl = (p_sdf->f[fn].ctrl<<2) | STEIM2_SPECIAL_MASK;

    while (points_remaining > 0) {
	/*  Pack the next available datapoints into the most compact form.  */
	if (BIT4PACK(ipt,points_remaining)) {
	    PACK(4,7,0x0000000f,02)
	    if (swapflag) swab4 ((int *)&p_sdf->f[fn].w[wn].fw);
	    mask = STEIM2_567_MASK;
	    points_remaining -= 7;
	}
	else if (BIT5PACK(ipt,points_remaining)) {
	    PACK(5,6,0x0000001f,01)
	    if (swapflag) swab4 ((int *)&p_sdf->f[fn].w[wn].fw);
	    mask = STEIM2_567_MASK;
	    points_remaining -= 6;
	}
	else if (BIT6PACK(ipt,points_remaining)) {
DATA_HDR *decode_hdr_sdr
   (SDR_HDR	*ihdr,		/* input SDR header.			*/
    int		maxbytes)	/* max # bytes in buffer.		*/
{
    char tmp[80];
    DATA_HDR *ohdr;
    BS *bs;			/* ptr to blockette structure.		*/
    char *p;
    char *pc;
    int i, next_seq;
    int seconds, usecs;
    int swapflag;
    int		itmp[2];
    short int	stmp[2];
    unsigned short int ustmp[2];
    int		wo;

    qlib2_errno = 0;
    if (my_wordorder < 0) get_my_wordorder();

    /* Perform data integrity check, and pick out pertinent header info.*/
    if (! (is_data_hdr_ind (ihdr->data_hdr_ind) || is_vol_hdr_ind (ihdr->data_hdr_ind))) {
	/*  Don't have a data header.  See if the entire header is	*/
	/*  composed of NULLS.  If so, print warning and return NULL.	*/
	/*  Some early Quanterras output a spurious block with null	*/
	/*  header info every 16 blocks.  That block should be ignored.	*/
	if (allnull((char *)ihdr, sizeof(SDR_HDR))) {
	    return ((DATA_HDR *)NULL);
	}
	else {
	    qlib2_errno = 1;
	    return ((DATA_HDR *)NULL);
	}
    }

    if ((ohdr = new_data_hdr()) == NULL) return (NULL);
    ohdr->record_type = ihdr->data_hdr_ind;
    ohdr->seq_no = atoi (charncpy (tmp, ihdr->seq_no, 6) );

    /* Handle volume header.					    */
    /* Return a pointer to a DATA_HDR structure containing blksize. */
    /* Save actual blockette for later use.			    */
    if (is_vol_hdr_ind(ihdr->data_hdr_ind)) {
	/* Get blksize from volume header.			    */
	p = (char *)ihdr+8;
	ohdr->blksize = 4096;	/* default tape blksize.	    */
	/* Put volume blockette number in data_type field.	    */
	ohdr->data_type = atoi (charncpy (tmp, p, 3));
	switch (ohdr->data_type) {
	  int ok;
	  case 5:
	  case 8:
	  case 10:
	    ohdr->blksize = (int)pow(2.0,atoi(charncpy(tmp,p+11,2)));
	    ok = add_blockette (ohdr, p, ohdr->data_type, 
			   atoi(charncpy(tmp,p+3,4)), my_wordorder, 0);
	    if (! ok) {
		qlib2_errno = 2;
		free_data_hdr(ohdr);
		return ((DATA_HDR *)NULL);
	    }
	    break;
	  default:
	    break;
	}
	return (ohdr);
    }

    /* Determine word order of the fixed record header.			*/
    if ((wo = wordorder_from_time((unsigned char *)&(ihdr->time))) < 0) {
	qlib2_errno = 3;
	free_data_hdr (ohdr);
	return ((DATA_HDR *)NULL);
    }
    ohdr->hdr_wordorder = wo;
    ohdr->data_wordorder = ohdr->hdr_wordorder;
    swapflag = (ohdr->hdr_wordorder != my_wordorder);
    charncpy (ohdr->station_id, ihdr->station_id, 5);
    charncpy (ohdr->location_id, ihdr->location_id, 2);
    charncpy (ohdr->channel_id, ihdr->channel_id, 3);
    charncpy (ohdr->network_id, ihdr->network_id, 2);
    trim (ohdr->station_id);
    trim (ohdr->location_id);
    trim (ohdr->channel_id);
    trim (ohdr->network_id);
    ohdr->hdrtime = decode_time_sdr(ihdr->time, ohdr->hdr_wordorder);
    if (swapflag) {
	/* num_samples.	*/
	ustmp[0] = ihdr->num_samples;
	swab2 ((short int *)&ustmp[0]);
	ohdr->num_samples = ustmp[0];
	/* data_rate	*/
	stmp[0] = ihdr->sample_rate_factor;
	stmp[1] = ihdr->sample_rate_mult;
	swab2 ((short int *)&stmp[0]);
	swab2 ((short int *)&stmp[1]);
	ohdr->sample_rate = stmp[0];
	ohdr->sample_rate_mult = stmp[1];
	/* num_ticks_correction. */
	itmp[0] = ihdr->num_ticks_correction;
	swab4 (&itmp[0]);
	ohdr->num_ticks_correction = itmp[0];
	/* first_data	*/
	ustmp[0] = ihdr->first_data;
	swab2 ((short int *)&ustmp[0]); 
	ohdr->first_data = ustmp[0];
	/* first_blockette */
	ustmp[1] = ihdr->first_blockette;
	swab2 ((short int *)&ustmp[1]);
	ohdr->first_blockette = ustmp[1];
    }
    else {
	ohdr->num_samples = ihdr->num_samples;
	ohdr->sample_rate = ihdr->sample_rate_factor;
	ohdr->sample_rate_mult = ihdr->sample_rate_mult;
	ohdr->num_ticks_correction = ihdr->num_ticks_correction;
	ohdr->first_data = ihdr->first_data;
	ohdr->first_blockette = ihdr->first_blockette;
    }

    /*	WARNING - may need to convert flags to independent format	*/
    /*	if we ever choose a different flag format for the DATA_HDR.	*/
    ohdr->activity_flags = ihdr->activity_flags;
    ohdr->io_flags = ihdr->io_flags;
    ohdr->data_quality_flags = ihdr->data_quality_flags;

    ohdr->num_blockettes = ihdr->num_blockettes;
    ohdr->data_type = 0;		/* assume unknown datatype.	*/
    ohdr->pblockettes = (BS *)NULL;	/* Do not parse blockettes here.*/

    if (ohdr->num_blockettes == 0) ohdr->pblockettes = (BS *)NULL;
    else {
	if (read_blockettes (ohdr, (char *)ihdr) != 1) {
	    free ((char *)ohdr);
	    return ((DATA_HDR *)NULL);
	}
    }

    /*	Process any blockettes that follow the fixed data header.	*/
    /*	If a blockette 1000 exists, fill in the datatype.		*/
    /*	Otherwise, leave the datatype as unknown.			*/
    ohdr->data_type = UNKNOWN_DATATYPE;
    ohdr->num_data_frames = -1;
    if ((bs=find_blockette(ohdr, 1000))) {
	/* Ensure we have proper output blocksize in the blockette.	*/
	BLOCKETTE_1000 *b1000 = (BLOCKETTE_1000 *) bs->pb;
	ohdr->data_type = b1000->format;
	ohdr->blksize = (int)pow(2.0,b1000->data_rec_len);
	ohdr->data_wordorder = b1000->word_order;
    }
    if ((bs=find_blockette(ohdr, 1001))) {
	/* Add in the usec99 field to the hdrtime.			*/
	BLOCKETTE_1001 *b1001 = (BLOCKETTE_1001 *) bs->pb;
	ohdr->hdrtime = add_time (ohdr->hdrtime, 0, b1001->usec99);
	ohdr->num_data_frames = b1001->frame_count;
    }

    /*	If the time correction has not already been added, we should	*/
    /*	add it to the begtime.  Do NOT change the ACTIVITY flag, since	*/
    /*	it refers to the hdrtime, NOT the begtime/endtime.		*/
    ohdr->begtime = ohdr->hdrtime;
    if ( ohdr->num_ticks_correction != 0 && 
	((ohdr->activity_flags & ACTIVITY_TIME_CORR_APPLIED) == 0) ) {
	ohdr->begtime = add_dtime (ohdr->begtime,
				   (double)ohdr->num_ticks_correction * USECS_PER_TICK);
    }
    /* Compute endtime.  Use precise sample interval in blockette 100.	*/
    /* For client convenience convert it to my_wordorder if not already.*/
    if ((bs=find_blockette(ohdr, 100))) {
	double actual_rate, dusecs;
        BLOCKETTE_100 *b = (BLOCKETTE_100 *) bs->pb;
	if (bs->wordorder != my_wordorder) {
	    swab_blockette (bs->type, bs->pb, bs->len);
	    bs->wordorder = my_wordorder;
	}
	actual_rate = b->actual_rate;
	dusecs = ((double)((ohdr->num_samples-1)/actual_rate))*USECS_PER_SEC;
	ohdr->endtime = add_dtime (ohdr->begtime,  dusecs);
	ohdr->rate_spsec = actual_rate;
    }
    else {
	time_interval2(ohdr->num_samples - 1, ohdr->sample_rate, ohdr->sample_rate_mult,
		       &seconds, &usecs);
	ohdr->endtime = add_time(ohdr->begtime, seconds, usecs);
    }

    /*	Attempt to determine blocksize if current setting is 0.		*/
    /*	We can detect files of either 512 byte or 4K byte blocks.	*/
    if (ohdr->blksize == 0) {
	for (i=1; i< 4; i++) {
	    pc = ((char *)(ihdr)) + (i*512);
	    if (pc - (char *)(ihdr) >= maxbytes) break;
	    if ( allnull ( pc,sizeof(SDR_HDR)) ) continue;
	    next_seq = atoi (charncpy (tmp, ((SDR_HDR *)pc)->seq_no, 6) );
	    if (next_seq == ohdr->seq_no + i) {
		ohdr->blksize = 512;
		break;
	    }
	}
	/* Can't determine the blocksize.  Assume default.		*/
	/* Assume all non-MiniSEED SDR data is in STEIM1 format.	*/
	/* Assume data_wordorder == hdr_wordorder.			*/
	if (ohdr->blksize == 0) ohdr->blksize = (maxbytes >= 1024) ? 4096 : 512;
	if (ohdr->num_samples > 0 && ohdr->sample_rate != 0) {
	    ohdr->data_type = STEIM1;
	    ohdr->num_data_frames = (ohdr->blksize-ohdr->first_data)/sizeof(FRAME);
	    ohdr->data_wordorder = ohdr->hdr_wordorder;
	}
    }

    /* Fill in num_data_frames, since there may not be a blockette 1001.*/
    if (IS_STEIM_COMP(ohdr->data_type) && ohdr->num_samples > 0 && 
	ohdr->sample_rate != 0 && ohdr->num_data_frames < 0) {
	ohdr->num_data_frames = (ohdr->blksize-ohdr->first_data)/sizeof(FRAME);
    }
	
    return (ohdr);
}
int init_sdr_hdr
   (SDR_HDR	*sh,		/* ptr to space for sdr data hdr.	*/
    DATA_HDR	*hdr,		/* initial DATA_HDR for sdr record.	*/
    BS		*extra_bs)	/* ptr to block-specific blockettes.	*/
{
    int status = 0;
    int blockette_space;	/* # of bytes required for blockettes.	*/
    int n_extra_bs;		/* # of extra blockettes.		*/
    BS *bs;			/* ptr to blockette structure.		*/
    BS *last_bs;		/* ptr to last permanent blockette.	*/
    int align;			/* alignment in bytes required for data.*/
    int swapflag;		/* flag to indicate byteswapping.	*/
    MS_ATTR attr;
    int blksize = hdr->blksize;


    if (my_wordorder < 0) 
	get_my_wordorder();
    swapflag = (my_wordorder != hdr->hdr_wordorder);

    /* Determine the space required for all of the blockettes.		*/
    for (bs=hdr->pblockettes, blockette_space=0, last_bs=NULL; 
	 bs!=NULL; 
	 last_bs=bs, bs=bs->next) {
	blockette_space += bs->len + ((bs->len%4) ? 4-(bs->len%4) : 0);
    }
    for (bs=extra_bs, n_extra_bs=0; bs!=NULL; bs=bs->next, n_extra_bs++) {
	blockette_space += bs->len + ((bs->len%4) ? 4-(bs->len%4) : 0);
    }

    /* Temporarily add the list of extra blockettes to the list of	*/
    /* permanent blockettes.						*/
    if (extra_bs) {
	if (last_bs) last_bs->next = extra_bs;
	else hdr->pblockettes = extra_bs;
	hdr->num_blockettes += n_extra_bs;
    }

    /* Ensure that first_data points to appropriate offset for data.	*/
    /* Some data formats (eg the STEIM compressed formats) require	*/
    /* first_data to be on a frame boundary.				*/
    attr = get_ms_attr(hdr);
    if (attr.alignment == 0) return (MS_ERROR);
    align = attr.alignment;
    hdr->first_data = ((sizeof(SDR_HDR)+blockette_space+align-1)/align)*align;

    /* Update any blockettes that have block-specific info.		*/
    if ((bs=find_blockette(hdr, 1000))) {
	/* Ensure we have proper data in the blockette.			*/
	BLOCKETTE_1000 *b1000 = (BLOCKETTE_1000 *) bs->pb;
	/* These are all byte values, so I can ignore wordorder.	*/
	b1000->data_rec_len = roundoff(log2((double)blksize));
	b1000->format = hdr->data_type;
	b1000->word_order = hdr->data_wordorder;
    }
    if ((bs=find_blockette(hdr, 1001))) {
	/* Ensure we have proper data in the blockette.			*/
	/* Mark all frames as being in use.				*/
	BLOCKETTE_1001 *b1001 = (BLOCKETTE_1001 *) bs->pb;
	/* These are all byte values, so I can ignore wordorder.	*/
	b1001->frame_count = hdr->num_data_frames;
	b1001->usec99 = hdr->hdrtime.usec % 100;
    }
    
    /* Create the SDR fixed data header and data blockettes.		*/

    /* Parts of the header that do not change from block to block.	*/
    sh->space_1 = ' ';
    capnstr(sh->station_id,hdr->station_id,5);
    capnstr(sh->channel_id,hdr->channel_id,3);
    capnstr(sh->network_id,hdr->network_id,2);
    capnstr(sh->location_id,hdr->location_id,2);
    sh->sample_rate_factor = hdr->sample_rate;
    sh->sample_rate_mult = (hdr->sample_rate) ? hdr->sample_rate_mult : 0;

    /*  Parts of the header that change with each block.		*/
    sh->data_hdr_ind = hdr->record_type;
    capnint(sh->seq_no,hdr->seq_no,6);
    sh->time = encode_time_sdr(hdr->hdrtime, hdr->hdr_wordorder);
    sh->activity_flags = hdr->activity_flags;
    sh->io_flags = hdr->io_flags;
    sh->data_quality_flags = hdr->data_quality_flags;
    sh->num_samples = 0;
    sh->num_ticks_correction = hdr->num_ticks_correction;

    /* Parts of the header that depend on the blockettes.		*/
    sh->first_data = hdr->first_data;
    sh->num_blockettes = hdr->num_blockettes;
    sh->first_blockette = hdr->first_blockette;

    /*	Output any data blockettes.					*/
    if (hdr->num_blockettes > 0) {
	write_blockettes(hdr, (char *)sh);
    }

    /* Unlink the extra blockettes from the data_hdr.			*/
    if (extra_bs) {
	if (last_bs) last_bs->next = NULL;
	else hdr->pblockettes = NULL;
	hdr->num_blockettes -= n_extra_bs;
    }

    if (swapflag) {
	swab2 ((short int *)&sh->num_samples);
	swab2 ((short int *)&sh->sample_rate_factor);
	swab2 ((short int *)&sh->sample_rate_mult);
	swab2 ((short int *)&sh->first_data);
	swab2 ((short int *)&sh->first_blockette);
	swab4 ((int *)&sh->num_ticks_correction);
    }

    /* Zero any space between the end of the blockettes and first_data.	*/
    memset ((char*)sh + (sizeof(SDR_HDR)+blockette_space), 0,
	    hdr->first_data - (sizeof(SDR_HDR)+blockette_space));

    /* Return status our SDR header creation.				*/
    return (status);
}
int read_ms_bkt
   (DATA_HDR	*hdr,		/* data_header structure.		*/
    char	*buf,		/* ptr to fixed data header.		*/
    FILE	*fp)		/* FILE pointer for input file.		*/
{
    BS		*bs, *pbs;
    int		offset, i, bl_limit;
    SEED_UWORD	bl_len, bl_next, bl_type;
    int		bh_len = sizeof(BLOCKETTE_HDR);
    int		blksize = 0;
    int		preread = 0;    /* # bytes of blockette data preread.	*/

    if (my_wordorder < 0) get_my_wordorder();
    bs = pbs = (BS *)NULL;
    offset = hdr->first_blockette;
    hdr->pblockettes = (BS *)NULL;
    bl_next = 0;

    /*	Run through each blockette, allocate a linked list structure	*/
    /*	for it, and verify that the blockette structures are OK.	*/
    /*	There is a LOT of checking to ensure proper structure.		*/
    for (i=0; i<hdr->num_blockettes; i++) {

	if (i > 0 && bl_next == 0) {
	    fprintf (stderr, "Error: zero offset to next blockette\n");
	    fflush (stderr);
	    if (QLIB2_CLASSIC) exit(1);
	    return (MS_ERROR);
	}

	if ( (bs=(BS *)malloc(sizeof(BS))) == NULL ) {
	    fprintf (stderr, "Error: unable to malloc BS\n");
	    if (QLIB2_CLASSIC) exit(1);
	    return (QLIB2_MALLOC_ERROR);
	}
	bs->next = (BS *)NULL;
	if (i == 0) hdr->pblockettes = bs;
	else pbs->next = bs;
	pbs = bs;

	/*  Read blockette header.					*/
	if (fread (buf+offset, bh_len, 1, fp) != 1) 
	    return (EOF);
	preread = 0;

	/*  Decide how much space the blockette takes up.  If we know 	*/
	/*  blockette type, then allocate the appropriate space.	*/
	/*  Otherwise, determine the required space by the offset to	*/
	/*  the next blockette, or by the offset to the first data if	*/
	/*  this is the last blockette.					*/
	/*  If there is not data, then ensure that we know the length	*/
	/*  of the blockette.  If not, consider it to be a fatal error,	*/
	/*  since we have no idea how long it should be.		*/
	/*								*/
	/*  We cannot allow it to extend to the blksize, since we use	*/
	/*  this routine to process blockettes from packed miniSEED	*/
	/*  files.  Packed miniSEED files contain records that are a	*/
	/*  multiple of the packsize (currently 128 bytes) with a block	*/
	/*  whose size is specified in the b1000 blksize field.		*/
	bl_type = ((BLOCKETTE_HDR *)(buf+offset))->type;
	bl_next = ((BLOCKETTE_HDR *)(buf+offset))->next;
	if (hdr->hdr_wordorder != my_wordorder) {
	    swab2 ((short int *)&bl_type);
	    swab2 ((short int *)&bl_next);
	}
	bl_limit = (bl_next) ? bl_next : (hdr->first_data) ? hdr->first_data : 0;
	switch (bl_type) {
	  case 100: bl_len = sizeof (BLOCKETTE_100); break;
	  case 200: bl_len = sizeof (BLOCKETTE_200); break;
	  case 201: bl_len = sizeof (BLOCKETTE_201); break;
	  case 300: bl_len = sizeof (BLOCKETTE_300); break;
	  case 310: bl_len = sizeof (BLOCKETTE_310); break;
	  case 320: bl_len = sizeof (BLOCKETTE_320); break;
	  case 390: bl_len = sizeof (BLOCKETTE_390); break;
	  case 395: bl_len = sizeof (BLOCKETTE_395); break;
	  case 400: bl_len = sizeof (BLOCKETTE_400); break;
	  case 405: bl_len = sizeof (BLOCKETTE_405); break;
	  case 500: bl_len = sizeof (BLOCKETTE_500); break;
	  case 1000: bl_len = sizeof (BLOCKETTE_1000); break;
	  case 1001: bl_len = sizeof (BLOCKETTE_1001); break;
	  /* Variable length blockettes.  Preserve original length,	*/
	  /* even though it may not is divisible by 4.		*/
	  /* It is up to the user to ensure that that blockettes	*/
	  /* have 4 byte alignment in a SEED data record.		*/
	  case 2000: 
	    /* Length of blockette 2000 is stored in first word of blockette.	*/
	    preread = 2;
	    if (fread (buf+offset+bh_len, preread, 1, fp) != 1) 
		return (EOF);
	    bl_len = ((BLOCKETTE_2000 *)(buf+offset))->blockette_len; 
	    if (hdr->hdr_wordorder != my_wordorder) {
		swab2 ((short int *)&bl_len);
	    }
	    break;
	  default:
	    fprintf (stderr, "Warning: unknown blockette %d\n",bl_type);
	    bl_len = 0;
	    break;
	}

	/* Perform integrity checks on blockette.			*/
	if (bl_len != 0) {
	    /* Known blockettes:					*/
	    /* Check that the presumed blockette length is correct.	*/
	    if (bl_limit > 0 && (int)bl_len > bl_limit-offset) {
		/* Warning only if blockette is too short.		*/
		/* Allow padding between blockettes.			*/
		fprintf (stderr, "Warning: short blockette %d len=%d, expected len=%d\n",
			 bl_type, bl_limit-offset, bl_len);
	    }
	    /* Be safe and extend the effective length of the blockette	*/
	    /* to the limit (next blockette or first data) if there is	*/
	    /* a limit.							*/
	    bl_len = (bl_limit) ? bl_limit - offset : bl_len;
	    /* Check that we do not run into the data portion of record.*/
	    if (hdr->first_data != 0 && (int)bl_len+offset > hdr->first_data) {
		fprintf (stderr, "Warning: blockette %d	at offset=%d len=%d first_data=%d\n",
			 bl_type, bl_limit-offset, bl_len, hdr->first_data);
		bl_len = bl_limit - offset;
	    }
	}
	else {
	    /* Unknown blockettes:					*/
	    if (bl_limit == 0) {
		fprintf (stderr, "Warning: unknown blockette and no length limit\n");
		return (-1);
	    }
	    /* For unknown blockettes ensure that we have a max len.	*/
	    bl_len = bl_limit - offset;
	}

	if ((bs->pb = (char *)malloc(bl_len))==NULL) {
	    fprintf (stderr, "unable to malloc blockettd\n");
	    return (-1);
	}
	/* Read the body of the blockette, and copy entire blockette.	*/
	if (fread(buf+offset+bh_len+preread, bl_len-bh_len-preread, 1, fp) != 1)
	    return(-1);
	memcpy (bs->pb,buf+offset,bl_len);
	bs->len = bl_len;
	bs->type = bl_type;
	bs->wordorder = hdr->hdr_wordorder;
	if (bl_type == 1000) {
	    blksize = (int)pow(2., (double)((BLOCKETTE_1000 *)(buf+offset))->data_rec_len);
	}
	offset += bl_len;
	preread = 0;
    }

    /* Ensure there are no more blockettes. */
    if (bl_next != 0) {
	fprintf (stderr, "extra blockette found\n");
	return(-1);
    }
    return (offset);
}
DATA_HDR *decode_fixed_data_hdr
    (SDR_HDR	*ihdr)		/* MiniSEED header.			*/
{
    char	tmp[80];
    DATA_HDR	*ohdr;
    int		seconds, usecs;
    char	*p;
    int		swapflag;	
    int		itmp[2];
    short int	stmp[2];
    unsigned short int ustmp[2];
    int		wo;

    if (my_wordorder < 0) get_my_wordorder();

    /* Perform data integrity check, and pick out pertinent header info.*/
    if (! (is_data_hdr_ind (ihdr->data_hdr_ind) || is_vol_hdr_ind (ihdr->data_hdr_ind))) {
	return ((DATA_HDR *)NULL);
    }

    if ((ohdr = new_data_hdr()) == NULL) return (NULL);
    ohdr->record_type = ihdr->data_hdr_ind;
    ohdr->seq_no = atoi (charncpy (tmp, ihdr->seq_no, 6) );

    /* Handle volume header.					    */
    /* Return a pointer to a DATA_HDR structure containing blksize. */
    /* Save actual blockette for later use.			    */
    if (is_vol_hdr_ind(ihdr->data_hdr_ind)) {
	if ((ohdr = new_data_hdr()) == NULL) return (NULL);
	ohdr->record_type = ihdr->data_hdr_ind;
	ohdr->seq_no = atoi (charncpy (tmp, ihdr->seq_no, 6) );
	ohdr->blksize = 4096;	/* default tape blksize.	    */
	p = (char *)ihdr+8;	/* point to start of blockette.	    */
	ohdr->data_type = atoi(charncpy(tmp,p,3));
	switch (ohdr->data_type) {
	  case 5:
	  case 8:
	  case 10:
	    ohdr->blksize = (int)pow(2.0,atoi(charncpy(tmp,p+11,2)));
	    /* Do not add the blockette here, since we are not		*/
	    /* assured that the entire blockette is in this buffer.	*/
	    break;
	  default:
	    break;
	}
	return (ohdr);
    }

    /* Determine word order of the fixed record header.			*/
    if ((wo = wordorder_from_time((unsigned char *)&(ihdr->time)))< 0) {
	free_data_hdr (ohdr);
	return ((DATA_HDR *)NULL);
    }
    ohdr->hdr_wordorder = wo;
    ohdr->data_wordorder = ohdr->hdr_wordorder;
    swapflag = (ohdr->hdr_wordorder != my_wordorder);
    charncpy (ohdr->station_id, ihdr->station_id, 5);
    charncpy (ohdr->location_id, ihdr->location_id, 2);
    charncpy (ohdr->channel_id, ihdr->channel_id, 3);
    charncpy (ohdr->network_id, ihdr->network_id, 2);
    trim (ohdr->station_id);
    trim (ohdr->location_id);
    trim (ohdr->channel_id);
    trim (ohdr->network_id);
    ohdr->hdrtime = ohdr->begtime = decode_time_sdr(ihdr->time, ohdr->hdr_wordorder);
    if (swapflag) {
	/* num_samples.	*/
	ustmp[0] = ihdr->num_samples;
	swab2 ((short int *)&ustmp[0]);
	ohdr->num_samples = ustmp[0];
	/* data_rate	*/
	stmp[0] = ihdr->sample_rate_factor;
	stmp[1] = ihdr->sample_rate_mult;
	swab2 (&stmp[0]);
	swab2 (&stmp[1]);
	ohdr->sample_rate = stmp[0];
	ohdr->sample_rate_mult = stmp[1];
	/* num_ticks_correction. */
	itmp[0] = ihdr->num_ticks_correction;
	swab4 (&itmp[0]);
	ohdr->num_ticks_correction = itmp[0];
	/* first_data	*/
	ustmp[0] = ihdr->first_data;
	swab2 ((short int *)&ustmp[0]); 
	ohdr->first_data = ustmp[0];
	/* first_blockette */
	ustmp[1] = ihdr->first_blockette;
	swab2 ((short int *)&ustmp[1]);
	ohdr->first_blockette = ustmp[1];
    }
    else {
	ohdr->num_samples = ihdr->num_samples;
	ohdr->sample_rate = ihdr->sample_rate_factor;
	ohdr->sample_rate_mult = ihdr->sample_rate_mult;
	ohdr->num_ticks_correction = ihdr->num_ticks_correction;
	ohdr->first_data = ihdr->first_data;
	ohdr->first_blockette = ihdr->first_blockette;
    }

    /*	WARNING - may need to convert flags to independent format	*/
    /*	if we ever choose a different flag format for the DATA_HDR.	*/
    ohdr->activity_flags = ihdr->activity_flags;
    ohdr->io_flags = ihdr->io_flags;
    ohdr->data_quality_flags = ihdr->data_quality_flags;

    ohdr->num_blockettes = ihdr->num_blockettes;
    ohdr->data_type = 0;		/* assume unknown datatype.	*/
    ohdr->pblockettes = (BS *)NULL;	/* Do not parse blockettes here.*/

    /*	If the time correction has not already been added, we should	*/
    /*	add it to the begtime.  Do NOT change the ACTIVITY flag, since	*/
    /*	it refers to the hdrtime, NOT the begtime/endtime.		*/
    if ( ohdr->num_ticks_correction != 0 && 
	((ohdr->activity_flags & ACTIVITY_TIME_CORR_APPLIED) == 0) ) {
	ohdr->begtime = add_dtime (ohdr->begtime, 
				  (double)ohdr->num_ticks_correction * USECS_PER_TICK);
    }
    time_interval2(ohdr->num_samples - 1, ohdr->sample_rate, ohdr->sample_rate_mult,
		  &seconds, &usecs);
    ohdr->endtime = add_time(ohdr->begtime, seconds, usecs);

    return(ohdr);
}
int read_blockettes
   (DATA_HDR	*hdr,		/* data_header structure.		*/
    char	*str)		/* ptr to fixed data header.		*/
{
    BS *bs, *pbs;
    int offset, i;
    SEED_UWORD bl_len, bl_next, bl_type;

    if (my_wordorder < 0) get_my_wordorder();
    bs = pbs = (BS *)NULL;
    offset = hdr->first_blockette;
    hdr->pblockettes = (BS *)NULL;
    bl_next = 0;

    /*	Run through each blockette, allocate a linked list structure	*/
    /*	for it, and verify that the blockette structures are OK.	*/
    /*	There is a LOT of checking to ensure proper structure.		*/
    for (i=0; i<hdr->num_blockettes; i++) {

	if (i > 0 && bl_next == 0) {
	    fprintf (stderr, "Error: zero offset to next blockette\n");
	    fflush (stderr);
	    if (QLIB2_CLASSIC) exit(1);
	    return (MS_ERROR);
	}

	if ( (bs=(BS *)malloc(sizeof(BS))) == NULL ) {
	    fprintf (stderr, "Error: unable to malloc BS\n");
	    fflush (stderr);
	    if (QLIB2_CLASSIC) exit(1);
	    return (QLIB2_MALLOC_ERROR);
	}
	bs->next = (BS *)NULL;

	/*  Decide how much space the blockette takes up.		*/
	/*  In order to allow for variable blockette size for either	*/
	/*  newer SEED version or vendor-specific additions,		*/
	/*  attempt to determine the required space by the offset to	*/
	/*  the next blockette.  If this is the last blockette, 	*/
	/*  then just use the length of the blockette as it is defined.	*/
	bl_type = ((BLOCKETTE_HDR *)(str+offset))->type;
	bl_next = ((BLOCKETTE_HDR *)(str+offset))->next;
	if (hdr->hdr_wordorder != my_wordorder) {
	    swab2 ((short int *)&bl_type);
	    swab2 ((short int *)&bl_next);
	}
	if (bl_next > 0) {
	    bl_len = (bl_next-offset);
	}
	else {
	    /* No further blockettes.  Assume length of blockette structure.*/
	    switch (bl_type) {
	      /* Fixed length blockettes.	*/
	      case 100: bl_len = sizeof (BLOCKETTE_100); break;
	      case 200: bl_len = sizeof (BLOCKETTE_200); break;
	      case 201: bl_len = sizeof (BLOCKETTE_201); break;
	      case 300: bl_len = sizeof (BLOCKETTE_300); break;
	      case 310: bl_len = sizeof (BLOCKETTE_310); break;
	      case 320: bl_len = sizeof (BLOCKETTE_320); break;
	      case 390: bl_len = sizeof (BLOCKETTE_390); break;
	      case 395: bl_len = sizeof (BLOCKETTE_395); break;
	      case 400: bl_len = sizeof (BLOCKETTE_400); break;
	      case 405: bl_len = sizeof (BLOCKETTE_405); break;
	      case 500: bl_len = sizeof (BLOCKETTE_500); break;
	      case 1000: bl_len = sizeof (BLOCKETTE_1000); break;
	      case 1001: bl_len = sizeof (BLOCKETTE_1001); break;
	      /* Variable length blockettes.  Preserve original length,	*/
	      /* even though it may not is divisible by 4.		*/
	      /* It is up to the user to ensure that that blockettes	*/
	      /* have 4 byte alignment in a SEED data record.		*/
	      case 2000: 
		bl_len = ((BLOCKETTE_2000 *)(str+offset))->blockette_len; 
		if (hdr->hdr_wordorder != my_wordorder) {
		    swab2 ((short int *)&bl_len);
		}
		break;
	      default: bl_type = 0; bl_len = 0; break;
	    }
	    /* Ensure that the blockette length does not exceed space	*/
	    /* available for it after the header and before first_data.	*/
	    if (hdr->first_data > 0 && hdr->first_data - offset > 0 && 
		(int)bl_len > hdr->first_data - offset)
		bl_len = hdr->first_data - offset;
	}

	if (bl_next != 0 && bl_len != 0) {
	    /* Verify length for known blockettes when possible. */
/*::
	    if (bl_len != bl_next-offset) {
		fprintf (stderr, "Error: blockette %d apparent size %d does not match known length %d\n",
			 bl_type, bl_next-offset, bl_len);
		fflush (stderr);
		if (QLIB2_CLASSIC) exit(1);
		return (MS_ERROR);
	    }
::*/
	}
	else if (bl_len == 0 && bl_type == 0) {
	    /* Assume the blockette reaches to first data.  */
	    /* If first data == 0, then abort -- we don't know this blockette.	*/
	    if (hdr->first_data <= offset) {
		fprintf (stderr, "Unknown blockette type %d - unable to determine size\n",
			 ((BLOCKETTE_HDR *)(str+offset))->type);
		fflush (stderr);
		free ((char *)bs);
		continue;
	    }
	    else bl_len = hdr->first_data - offset;
	}
	if ((bs->pb = (char *)malloc(bl_len))==NULL) {
	    fprintf (stderr, "Error: unable to malloc blockette\n");
	    fflush (stderr);
	    if (QLIB2_CLASSIC) exit(1);
	    return (MS_ERROR);
	}
	memcpy (bs->pb,str+offset,bl_len);
	bs->len = bl_len;
	bs->type = bl_type;
	bs->wordorder = hdr->hdr_wordorder;
	offset += bl_len;
	if (i == 0) hdr->pblockettes = bs;
	else pbs->next = bs;
	pbs = bs;
    }

    /* Ensure there are no more blockettes. */
    if (bl_next != 0) {
	fprintf (stderr, "extra blockette found\n");
	fflush (stderr);
	return (QLIB2_CLASSIC ? 0 : MS_ERROR);
    }
    return (1);
}
Example #18
0
int f_get_my_wordorder (void)
#endif
{
    return (get_my_wordorder());
}
Example #19
0
int pack_steim1
   (SDF		*p_sdf,		/* ptr to SDR structure.		*/
    int		data[],		/* unpacked data array.			*/
    int		diff[],		/* unpacked diff array.			*/
    int		ns,		/* num_samples.				*/
    int		nf,		/* total number of data frames.		*/
    int		pad,		/* flag to specify padding to nf.	*/
    int		data_wordorder,	/* wordorder of data (NOT USED).	*/
    int		*pnframes,	/* number of frames actually packed.	*/
    int		*pnsamples)	/* number of samples actually packed.	*/
{
    int		points_remaining = ns;
    int		*minbits;	/* min bytes for difference.		*/
    int		i, j;
    int		mask;
    int		ipt = 0;	/* index of initial data to pack.	*/
    int		fn = 0;		/* index of initial frame to pack.	*/
    int		wn = 2;		/* index of initial word to pack.	*/
    int		itmp;
    short int	stmp;
    int		swapflag;
    int		nb;		/* number of minbits to compute.	*/
    int		max_samples_per_frame;

    if (my_wordorder < 0) get_my_wordorder();
    swapflag = (my_wordorder != data_wordorder);

    max_samples_per_frame = 4 * VALS_PER_FRAME;	/* steim1 compression.	*/
    nb = max_samples_per_frame * nf;
    if (nb > points_remaining) nb = points_remaining;

    minbits = NULL;
    minbits = (int *)malloc(nb * sizeof(int));
    if (minbits == NULL) {
	fprintf (stderr, "Error: mallocing minbits in pack_steim1\n");
	fflush (stderr);
	if (QLIB2_CLASSIC) exit(1);
	return (MS_ERROR);
    }
    for (i=0; i<nb; i++) MINBITS(diff[i],minbits[i]);
    
    p_sdf->f[fn].ctrl = 0;

    /*	Set new X0 value in first frame.				*/
    X0 = data[0];
    if (swapflag) swab4((int *)&X0);
    p_sdf->f[fn].ctrl = (p_sdf->f[fn].ctrl<<2) | STEIM1_SPECIAL_MASK;
    XN = data[ns-1];
    if (swapflag) swab4((int *)&XN);
    p_sdf->f[fn].ctrl = (p_sdf->f[fn].ctrl<<2) | STEIM1_SPECIAL_MASK;

    while (points_remaining > 0) {
	/*  Pack the next available data into the most compact form.	*/
	if (BYTEPACK(ipt,points_remaining)) {
	    mask = STEIM1_BYTE_MASK;
	    for (j=0; j<4; j++) p_sdf->f[fn].w[wn].byte[j] = diff[ipt++];
	    points_remaining -= 4;
	}
	else if (HALFPACK(ipt,points_remaining)) {
	    mask = STEIM1_HALFWORD_MASK;
	    for (j=0; j<2; j++) {
		stmp = diff[ipt++];
		if (swapflag) swab2 (&stmp);
		p_sdf->f[fn].w[wn].hw[j] = stmp;
	    }
	    points_remaining -= 2;
	}
	else {
	    mask = STEIM1_FULLWORD_MASK;
	    itmp = diff[ipt++];
	    if (swapflag) swab4 (&itmp);
	    p_sdf->f[fn].w[wn].fw = itmp;
	    points_remaining -= 1;
	}

	/* Append mask for this word to current mask.			*/
	p_sdf->f[fn].ctrl = (p_sdf->f[fn].ctrl<<2) | mask;

	/* Check for full frame or full block.				*/
	if (++wn >= VALS_PER_FRAME) {
	    if (swapflag) swab4 ((int *)&p_sdf->f[fn].ctrl);
	    /* Reset output index to beginning of frame.		*/
	    wn = 0;
	    /* If block is full, output block and reinitialize.		*/
	    if (++fn >= nf) break;
	    p_sdf->f[fn].ctrl = 0;
	}
    }

    /* Set new XN value in first frame.					*/
    XN = data[(ns-1)-points_remaining];
    if (swapflag) swab4((int *)&XN);

    /* End of data.  Pad current frame and optionally rest of block.	*/
    /* Do not pad and output a completely empty block.			*/
    if (! EMPTY_BLOCK(fn,wn)) {
	*pnframes = pad_steim_frame(p_sdf,fn,wn,nf,swapflag,pad);
    }
    else {
	*pnframes = 0;
    }
    *pnsamples = ns - points_remaining;
    free ((char *)minbits);
    return(0);
}