.
mseed2sac-2.2+ds1/Makefile 0000664 0000000 0000000 00000000511 13225706503 0015346 0 ustar 00root root 0000000 0000000
DIRS = libmseed src
all clean static install ::
@for d in $(DIRS) ; do \
echo "Running $(MAKE) $@ in $$d" ; \
if [ -f $$d/Makefile -o -f $$d/makefile ] ; \
then ( cd $$d && $(MAKE) $@ ) ; \
elif [ -d $$d ] ; \
then ( echo "ERROR: no Makefile/makefile in $$d for $(CC)" ) ; \
fi ; \
done
mseed2sac-2.2+ds1/Makefile.wat 0000664 0000000 0000000 00000000541 13225706503 0016143 0 ustar 00root root 0000000 0000000 #
# THIS FILE IS DEPRECATED AND WILL BE REMOVED IN A FUTURE RELEASE
#
# Wmake file - For Watcom's wmake
# Use 'wmake -f Makefile.wat'
all: .SYMBOLIC
cd libmseed
wmake -f Makefile.wat
cd ..\src
wmake -f Makefile.wat
cd ..
clean: .SYMBOLIC
cd libmseed
wmake -f Makefile.wat clean
cd ..\src
wmake -f Makefile.wat clean
cd ..
mseed2sac-2.2+ds1/Makefile.win 0000664 0000000 0000000 00000000417 13225706503 0016147 0 ustar 00root root 0000000 0000000 #
# Nmake file - For MS Visual C++ version
# Use 'nmake -f Makefile.win'
all:
cd libmseed
nmake -f Makefile.win
cd ..\src
nmake -f Makefile.win
cd ..
clean:
cd libmseed
nmake -f Makefile.win clean
cd ..\src
nmake -f Makefile.win clean
cd ..
mseed2sac-2.2+ds1/README.md 0000664 0000000 0000000 00000001570 13225706503 0015173 0 ustar 00root root 0000000 0000000 # mseed2sac - Convert miniSEED time series data to SAC
## Documentation
For usage infromation see the [mseed2sac manual](doc/mseed2sac.md) in the
'doc' directory.
## Downloading and building
The [releases](https://github.com/iris-edu/mseed2sac/releases) area
contains release versions.
In most Unix/Linux environments a simple 'make' will build the program.
The CC and CFLAGS environment variables can be used to configure
the build parameters.
If your system does not have zlib you can compile the program without
support for ZIP archive output: first type 'make' in the main
directory (the build will fail), then go to the 'src' directory and
type 'make nozip'.
In the Win32 environment the Makefile.win can be used with the nmake
build tool included with Visual Studio.
## Licensing
GNU GPL version 3. See included LICENSE file for details.
Copyright (c) 2017 Chad Trabant
mseed2sac-2.2+ds1/doc/ 0000775 0000000 0000000 00000000000 13225706503 0014456 5 ustar 00root root 0000000 0000000 mseed2sac-2.2+ds1/doc/mseed2sac.1 0000664 0000000 0000000 00000024155 13225706503 0016415 0 ustar 00root root 0000000 0000000 .TH MSEED2SAC 1 2017/09/29
.SH NAME
mseed2sac - miniSEED to SAC converter
.SH SYNOPSIS
.nf
mseed2sac [options] file1 [file2 file3 ...]
.fi
.SH DESCRIPTION
\fBmseed2sac\fP converts miniSEED waveform data to SAC format. The
output SAC file can be either ASCII or binary (either byte-order), the
default is binary with the same byte-order as the host computer. By
default all aspects of the input files are automatically detected.
If an input file name is prefixed with an '@' character the file is
assumed to contain a list of input data files, see \fIINPUT LIST
FILES\fP below.
A separate output file is written for each continuous time-series in
the input data. Output file names are of the form:
.nf
"Net.Sta.Loc.Chan.Qual.YYYY,DDD,HHMMSS.SAC"
For example:
"TA.ELFS..LHZ.R.2006,123,153619.SAC"
.fi
Files that would have the same file name due to having the same start
time will be kept separate by adding a digit to file name. The
\fI-O\fP argument changes this behavior to allow overwriting of
existing file names.
If the input file name is "-" input miniSEED records will be read
from standard input.
The SAC header variable KHOLE is used synonymously with the SEED
location code. Any location codes found in the input miniSEED or
metadata file are put into the KHOLE variable.
.SH OPTIONS
.IP "-V "
Print program version and exit.
.IP "-h "
Print program usage and exit.
.IP "-H "
Print extended program usage with all options and exit.
.IP "-v "
Be more verbose. This flag can be used multiple times ("-v -v" or
"-vv") for more verbosity.
.IP "-O "
Overwrite an existing files instead of generating new file names.
.IP "-k \fIlat/lon\fP"
Specify station coordinates to put into the output SAC file(s).
The argument format is "Latitude/Longitude" e.g. "47.66/-122.31".
Coordinates specified with this option override any coordinates found
in the metadata file.
.IP "-m \fImetafile\fP"
Specify a file containing metadata such as coordinates, elevation,
component orientation, scaling factor, etc. For each time-series
written any matching metadata will be added to the SAC header. See
\fIMETADATA FILES\fP below.
.IP "-M \fImetaline\fP"
Specify a "line" of metadata in the same format as expected for the
\fIMETADATA FILES\fP. This option may be specified multiple times.
.IP "-msi "
Convert any component inclination values in a metadata file from SEED
(dip) to SAC convention, this is a simple matter of adding 90 degrees.
.IP "-E \fIevent\fP"
Specify event parameters to add to the SAC file in the following
format:
.nf
"Time[/Lat][/Lon][/Depth][/Name]"
For example:
"2006,123,15:27:08.7/-20.33/-174.03/65.5/Tonga"
.fi
The parameters later in the string are optional.
.IP "-l \fIselectfile\fP"
Limit to miniSEED records that match a selection in the specified
file. The selection file contains parameters to match the network,
station, location, channel, quality and time range for input records.
This option only trims data to SEED record granularity, not sample
granularity. For more details see the \fBSELECTION FILE\fP section
below.
.IP "-f \fIformat\fP"
The default output format is binary SAC with the same byte order as
the host computer. This option forces the format for every output
file:
.nf
1 : Alphanumeric SAC format
2 : Binary SAC format, host byte order (default)
3 : Binary SAC format, little-endian
4 : Binary SAC format, big-endian
.fi
.IP "-N \fInetcode\fP"
Specify the network code to use, overriding any network code in the
input miniSEED.
.IP "-S \fIstation\fP"
Specify the station code to use, overriding any station code in the
input miniSEED.
.IP "-L \fIlocation\fP"
Specify the location code to use, overriding any location code in the
input miniSEED.
.IP "-C \fIchannel\fP"
Specify the channel code to use, overriding any channel code in the
input miniSEED.
.IP "-r \fIbytes\fP"
Specify the miniSEED record length in \fIbytes\fP, by default this is
autodetected.
.IP "-i "
Process each input file individually. By default all input files are
read and all data is buffered in memory before SAC files are written.
This allows time-series spanning mutilple input files to be merged and
written in a single SAC file. The intention is to use this option
when processing large amounts of data in order to keep memory usage
within reasonable limits.
.IP "-ic "
Process each input channel individually. Similar to the \fI-i\fP
option, except this instructs the program to create write SAC files
for each channel (determined when the input channel changes). Data
should be well ordered by channel for best results. This option can
be used to reduce memory usage for very large input files containing
many channels.
.IP "-dr "
Use the sampling rate derived from the start and end times and the
number of samples instead of the rate specified in the input data.
This is useful when the sample rate in the input data does not have
enough resolution to represent the true rate.
.IP "-z \fIzipfile\fP"
Create a ZIP archive containing all SAC files instead of writing
individual files. Each file is compressed with the deflate method.
Specify \fB"-"\fP (dash) to write ZIP archive to stdout.
.IP "-z0 \fIzipfile\fP"
Same as \fI"-z"\fP except do not compress the SAC files. Specify
\fB"-"\fP (dash) to write ZIP archive to stdout.
.SH "METADATA FILES"
A metadata file contains a list of station parameters, some of which
can be stored in SAC but not in miniSEED. Each line in a metadata
file should be a list of parameters in the order shown below. Each
parameter should be separated with a comma or a vertical bar (|).
\fbDIP CONVENTION:\fP When comma separators are used the dip field
(CMPINC) is assumed to be in the SAC convention (degrees down from
vertical up/outward), if vertical bars are used the dip field is
assumed to be in the SEED convention (degrees down from horizontal)
and converted to SAC convention.
\fBMetdata fields\fP:
.nf
Network (KNETWK)
Station (KSTNM)
Location (KHOLE)
Channel (KCMPNM)
Latitude (STLA)
Longitude (STLO)
Elevation (STEL), in meters [not currently used by SAC]
Depth (STDP), in meters [not currently used by SAC]
Component Azimuth (CMPAZ), degrees clockwise from north
Component Incident Angle (CMPINC), degrees from vertical
Instrument Name (KINST), up to 8 characters
Scale Factor (SCALE)
Scale Frequency, unused
Scale Units, unused
Sampling rate, unused
Start time, used for matching
End time, used for matching
Example with comma separators (with SAC convention dip):
------------------
#net,sta,loc,chan,lat,lon,elev,depth,azimuth,SACdip,instrument,scale,scalefreq,scaleunits,samplerate,start,end
IU,ANMO,00,BH1,34.945981,-106.457133,1671,145,328,90,Geotech KS-54000,3456610000,0.02,M/S,20,2008-06-30T20:00:00,2599-12-31T23:59:59
IU,ANMO,00,BH2,34.945981,-106.457133,1671,145,58,90,Geotech KS-54000,3344370000,0.02,M/S,20,2008-06-30T20:00:00,2599-12-31T23:59:59
IU,ANMO,00,BHZ,34.945981,-106.457133,1671,145,0,0,Geotech KS-54000,3275080000,0.02,M/S,20,2008-06-30T20:00:00,2599-12-31T23:59:59
IU,ANMO,10,BH1,34.945913,-106.457122,1767.2,48.8,64,90,Guralp CMG3-T,32805600000,0.02,M/S,40,2008-06-30T20:00:00,2599-12-31T23:59:59
IU,ANMO,10,BH2,34.945913,-106.457122,1767.2,48.8,154,90,Guralp CMG3-T,32655000000,0.02,M/S,40,2008-06-30T20:00:00,2599-12-31T23:59:59
IU,ANMO,10,BHZ,34.945913,-106.457122,1767.2,48.8,0,0,Guralp CMG3-T,33067200000,0.02,M/S,40,2008-06-30T20:00:00,2599-12-31T23:59:59
------------------
Example with vertical bar separators (with SEED convention dip):
------------------
#net|sta|loc|chan|lat|lon|elev|depth|azimuth|SEEDdip|instrument|scale|scalefreq|scaleunits|samplerate|start|end
IU|ANMO|00|BH1|34.945981|-106.457133|1671|145|328|0|Geotech KS-54000|3456610000|0.02|M/S|20|2008-06-30T20:00:00|2599-12-31T23:59:59
IU|ANMO|00|BH2|34.945981|-106.457133|1671|145|58|0|Geotech KS-54000|3344370000|0.02|M/S|20|2008-06-30T20:00:00|2599-12-31T23:59:59
IU|ANMO|00|BHZ|34.945981|-106.457133|1671|145|0|-90|Geotech KS-54000|3275080000|0.02|M/S|20|2008-06-30T20:00:00|2599-12-31T23:59:59
------------------
As a special case '--' can be used to match an empty location code.
.fi
For each time-series written, metadata from the first line with
matching source name parameters (network, station, location and
channel) and time window (if specified) will be inserted into the SAC
header. All parameters are optional except for the first four fields
specifying the source name parameters.
Simple wildcarding: for the source name parameters that will be
matched a '*' character in a field will match anything. The BHZ
metadata lines above, for example, can be (almost) summarized as:
.nf
IU,ANMO,*,BHZ,34.9459,-106.4571,1671,145,0,0,Geotech KS-54000,3456610000,0.02,M/S,20,2008-06-30T20:00:00,2599-12-31T23:59:59
.fi
.SH "SELECTION FILE"
A selection file is used to match input data records based on network,
station, location and channel information. Optionally a quality and
time range may also be specified for more refined selection. The
non-time fields may use the '*' wildcard to match multiple characters
and the '?' wildcard to match single characters. Character sets may
also be used, for example '[ENZ]' will match either E, N or Z.
The '#' character indicates the remaining portion of the line will be
ignored.
Example selection file entires (the first four fields are required)
.nf
#net sta loc chan qual start end
IU ANMO * BH?
II * * * Q
IU COLA 00 LH[ENZ] R
IU COLA 00 LHZ * 2008,100,10,00,00 2008,100,10,30,00
.fi
.SH "INPUT LIST FILES"
If an input file is prefixed with an '@' character the file is assumed
to contain a list of file for input. Multiple list files can be
combined with multiple input files on the command line. The last,
space separated field on each line is assumed to be the file name to
be read.
An example of a simple text list:
.nf
TA.ELFS..LHE.R.mseed
TA.ELFS..LHN.R.mseed
TA.ELFS..LHZ.R.mseed
.fi
.SH ABOUT SAC
Seismic Analysis Code (SAC) is a general purpose interactive program
designed for the study of sequential signals, especially timeseries
data. Originally developed at the Lawrence Livermore National
Laboratory the SAC software package is also available from IRIS.
.SH AUTHOR
.nf
Chad Trabant
IRIS Data Management Center
.fi
mseed2sac-2.2+ds1/doc/mseed2sac.md 0000664 0000000 0000000 00000026511 13225706503 0016653 0 ustar 00root root 0000000 0000000 # mseed2sac - miniSEED to SAC converter
1. [Name](#)
1. [Synopsis](#synopsis)
1. [Description](#description)
1. [Options](#options)
1. [Metadata Files](#metadata-files)
1. [Selection File](#selection-file)
1. [Input List Files](#input-list-files)
1. [About Sac](#about-sac)
1. [Author](#author)
## Synopsis
mseed2sac [options] file1 [file2 file3 ...]
## Description
mseed2sac converts miniSEED waveform data to SAC format. The output SAC file can be either ASCII or binary (either byte-order), the default is binary with the same byte-order as the host computer. By default all aspects of the input files are automatically detected.
If an input file name is prefixed with an '@' character the file is assumed to contain a list of input data files, see INPUT LIST FILES below.
A separate output file is written for each continuous time-series in the input data. Output file names are of the form:
"Net.Sta.Loc.Chan.Qual.YYYY,DDD,HHMMSS.SAC"
For example:
"TA.ELFS..LHZ.R.2006,123,153619.SAC"
Files that would have the same file name due to having the same start time will be kept separate by adding a digit to file name. The -O argument changes this behavior to allow overwriting of existing file names.
If the input file name is "-" input miniSEED records will be read from standard input.
The SAC header variable KHOLE is used synonymously with the SEED location code. Any location codes found in the input miniSEED or metadata file are put into the KHOLE variable.
## Options
-V
Print program version and exit.
-h
Print program usage and exit.
-H
Print extended program usage with all options and exit.
-v
Be more verbose. This flag can be used multiple times ("-v -v" or "-vv") for more verbosity.
-O
Overwrite an existing files instead of generating new file names.
-k lat/lon
Specify station coordinates to put into the output SAC file(s). The argument format is "Latitude/Longitude" e.g. "47.66/-122.31". Coordinates specified with this option override any coordinates found in the metadata file.
-m metafile
Specify a file containing metadata such as coordinates, elevation, component orientation, scaling factor, etc. For each time-series written any matching metadata will be added to the SAC header. see METADATA FILES below.
-msi
Convert any component inclination values in a metadata file from SEED (dip) to SAC convention, this is a simple matter of adding 90 degrees.
-E event
Specify event parameters to add to the SAC file in the following format:
"Time[/Lat][/Lon][/Depth][/Name]"
For example:
"2006,123,15:27:08.7/-20.33/-174.03/65.5/Tonga"
The parameters later in the string are optional.
-l selectfile
Limit to miniSEED records that match a selection in the specified file. The selection file contains parameters to match the network, station, location, channel, quality and time range for input records. This option only trims data to SEED record granularity, not sample granularity. For more details see the SELECTION FILE section below.
-f format
The default output format is binary SAC with the same byte order as the host computer. This option forces the format for every output file:
1 : Alphanumeric SAC format
2 : Binary SAC format, host byte order (default)
3 : Binary SAC format, little-endian
4 : Binary SAC format, big-endian
-N netcode
Specify the network code to use, overriding any network code in the input miniSEED.
-S station
Specify the station code to use, overriding any station code in the input miniSEED.
-L location
Specify the location code to use, overriding any location code in the input miniSEED.
-C channel
Specify the channel code to use, overriding any channel code in the input miniSEED.
-r bytes
Specify the miniSEED record length in bytes, by default this is autodetected.
-i
Process each input file individually. By default all input files are read and all data is buffered in memory before SAC files are written. This allows time-series spanning mutilple input files to be merged and written in a single SAC file. The intention is to use this option when processing large amounts of data in order to keep memory usage within reasonable limits.
-ic
Process each input channel individually. Similar to the -i option, except this instructs the program to create write SAC files for each channel (determined when the input channel changes). Data should be well ordered by channel for best results. This option can be used to reduce memory usage for very large input files containing many channels.
-dr
Use the sampling rate derived from the start and end times and the number of samples instead of the rate specified in the input data. This is useful when the sample rate in the input data does not have enough resolution to represent the true rate.
-z zipfile
Create a ZIP archive containing all SAC files instead of writing individual files. Each file is compressed with the deflate method. Specify "-" (dash) to write ZIP archive to stdout.
-z0 zipfile
Same as "-z" except do not compress the SAC files. Specify "-" (dash) to write ZIP archive to stdout.
## Metadata Files
A metadata file contains a list of station parameters, some of which can be stored in SAC but not in miniSEED. Each line in a metadata file should be a list of parameters in the order shown below. Each parameter should be separated with a comma or a vertical bar (|). DIP CONVENTION: When comma separators are used the dip field (CMPINC) is assumed to be in the SAC convention (degrees down from vertical up/outward), if vertical bars are used the dip field is assumed to be in the SEED convention (degrees down from horizontal) and converted to SAC convention.
Metdata fields:
Network (KNETWK)
Station (KSTNM)
Location (KHOLE)
Channel (KCMPNM)
Latitude (STLA)
Longitude (STLO)
Elevation (STEL), in meters [not currently used by SAC]
Depth (STDP), in meters [not currently used by SAC]
Component Azimuth (CMPAZ), degrees clockwise from north
Component Incident Angle (CMPINC), degrees from vertical
Instrument Name (KINST), up to 8 characters
Scale Factor (SCALE)
Scale Frequency, unused
Scale Units, unused
Sampling rate, unused
Start time, used for matching
End time, used for matching
Example with comma separators (with SAC convention dip):
------------------
#net,sta,loc,chan,lat,lon,elev,depth,azimuth,SACdip,instrument,scale,scalefreq,scaleunits,samplerate,start,end
IU,ANMO,00,BH1,34.945981,-106.457133,1671,145,328,90,Geotech KS-54000,3456610000,0.02,M/S,20,2008-06-30T20:00:00,2599-12-31T23:59:59
IU,ANMO,00,BH2,34.945981,-106.457133,1671,145,58,90,Geotech KS-54000,3344370000,0.02,M/S,20,2008-06-30T20:00:00,2599-12-31T23:59:59
IU,ANMO,00,BHZ,34.945981,-106.457133,1671,145,0,0,Geotech KS-54000,3275080000,0.02,M/S,20,2008-06-30T20:00:00,2599-12-31T23:59:59
IU,ANMO,10,BH1,34.945913,-106.457122,1767.2,48.8,64,90,Guralp CMG3-T,32805600000,0.02,M/S,40,2008-06-30T20:00:00,2599-12-31T23:59:59
IU,ANMO,10,BH2,34.945913,-106.457122,1767.2,48.8,154,90,Guralp CMG3-T,32655000000,0.02,M/S,40,2008-06-30T20:00:00,2599-12-31T23:59:59
IU,ANMO,10,BHZ,34.945913,-106.457122,1767.2,48.8,0,0,Guralp CMG3-T,33067200000,0.02,M/S,40,2008-06-30T20:00:00,2599-12-31T23:59:59
------------------
Example with vertical bar separators (with SEED convention dip):
------------------
#net|sta|loc|chan|lat|lon|elev|depth|azimuth|SEEDdip|instrument|scale|scalefreq|scaleunits|samplerate|start|end
IU|ANMO|00|BH1|34.945981|-106.457133|1671|145|328|0|Geotech KS-54000|3456610000|0.02|M/S|20|2008-06-30T20:00:00|2599-12-31T23:59:59
IU|ANMO|00|BH2|34.945981|-106.457133|1671|145|58|0|Geotech KS-54000|3344370000|0.02|M/S|20|2008-06-30T20:00:00|2599-12-31T23:59:59
IU|ANMO|00|BHZ|34.945981|-106.457133|1671|145|0|-90|Geotech KS-54000|3275080000|0.02|M/S|20|2008-06-30T20:00:00|2599-12-31T23:59:59
------------------
As a special case '--' can be used to match a blank (space, space) location code.
For each time-series written, metadata from the first line with matching source name parameters (network, station, location and channel) and time window (if specified) will be inserted into the SAC header. All parameters are optional except for the first four fields specifying the source name parameters.
Simple wildcarding: for the source name parameters that will be matched a '*' character in a field will match anything. The BHZ metadata lines above, for example, can be (almost) summarized as:
IU,ANMO,*,BHZ,34.9459,-106.4571,1671,145,0,0,Geotech KS-54000,3456610000,0.02,M/S,20,2008-06-30T20:00:00,2599-12-31T23:59:59
## Selection File
A selection file is used to match input data records based on network, station, location and channel information. Optionally a quality and time range may also be specified for more refined selection. The non-time fields may use the '*' wildcard to match multiple characters and the '?' wildcard to match single characters. Character sets may also be used, for example '[ENZ]' will match either E, N or Z. The '#' character indicates the remaining portion of the line will be ignored.
Example selection file entires (the first four fields are required)
#net sta loc chan qual start end
IU ANMO * BH?
II * * * Q
IU COLA 00 LH[ENZ] R
IU COLA 00 LHZ * 2008,100,10,00,00 2008,100,10,30,00
## Input List Files
If an input file is prefixed with an '@' character the file is assumed to contain a list of file for input. Multiple list files can be combined with multiple input files on the command line. The last, space separated field on each line is assumed to be the file name to be read.
An example of a simple text list:
TA.ELFS..LHE.R.mseed
TA.ELFS..LHN.R.mseed
TA.ELFS..LHZ.R.mseed
## About Sac
Seismic Analysis Code (SAC) is a general purpose interactive program designed for the study of sequential signals, especially timeseries data. Originally developed at the Lawrence Livermore National Laboratory the SAC software package is also available from IRIS.
## Author
Chad Trabant
IRIS Data Management Center
(man page 2017/04/03)
mseed2sac-2.2+ds1/src/ 0000775 0000000 0000000 00000000000 13225706503 0014500 5 ustar 00root root 0000000 0000000 mseed2sac-2.2+ds1/src/Makefile 0000664 0000000 0000000 00000001440 13225706503 0016137 0 ustar 00root root 0000000 0000000
# Build environment can be configured the following
# environment variables:
# CC : Specify the C compiler to use
# CFLAGS : Specify compiler options to use
# Required compiler parameters
REQCFLAGS = -I../libmseed
LOCALFLAGS =
BIN = mseed2sac
LDFLAGS = -L../libmseed
LDLIBS = -lm -lmseed
OBJS = $(BIN).o
nozip: LOCALFLAGS = -DNOFDZIP
all: $(BIN)
$(BIN): $(OBJS) fdzipstream.o
$(CC) $(CFLAGS) -o ../$(BIN) $(OBJS) fdzipstream.o $(LDFLAGS) $(LDLIBS) -lz
nozip: $(OBJS)
$(CC) $(CFLAGS) -o ../$(BIN) $(OBJS) $(LOCALFLAGS) $(LDFLAGS) $(LDLIBS)
clean:
rm -f $(OBJS) fdzipstream.o ../$(BIN)
# Implicit rule for building object files
%.o: %.c
$(CC) $(CFLAGS) $(REQCFLAGS) $(LOCALFLAGS) -c $<
install:
@echo
@echo "No install target, copy the executable(s) to desired location"
@echo
mseed2sac-2.2+ds1/src/Makefile.wat 0000664 0000000 0000000 00000001323 13225706503 0016731 0 ustar 00root root 0000000 0000000 #
# THIS FILE IS DEPRECATED AND WILL BE REMOVED IN A FUTURE RELEASE
#
# Wmake File - for Watcom's wmake
# Use 'wmake -f Makefile.wat'
.BEFORE
@set INCLUDE=.;$(%watcom)\H;$(%watcom)\H\NT
@set LIB=.;$(%watcom)\LIB386
cc = wcc386
cflags = -zq
lflags = OPT quiet OPT map LIBRARY ..\libmseed\libmseed.lib
cvars = $+$(cvars)$- -DWIN32 -DNOFDZIP
BIN = ..\mseed2sac.exe
INCS = -I..\libmseed
all: $(BIN)
$(BIN): mseed2sac.obj
wlink $(lflags) name $(BIN) file {mseed2sac.obj}
# Source dependencies:
mseed2sac.obj: mseed2sac.c sacformat.h
# How to compile sources:
.c.obj:
$(cc) $(cflags) $(cvars) $(INCS) $[@ -fo=$@
# Clean-up directives:
clean: .SYMBOLIC
del *.obj *.map $(BIN)
mseed2sac-2.2+ds1/src/Makefile.win 0000664 0000000 0000000 00000000631 13225706503 0016734 0 ustar 00root root 0000000 0000000 #
# Nmake file - Windows version
# Use 'nmake -f Makefile.win'
NODEBUG=1
INCS = /I..\libmseed
OPTS = -D_CRT_SECURE_NO_WARNINGS -DNOFDZIP
LIBS = ..\libmseed\libmseed.lib
BIN = ..\mseed2sac.exe
all: $(BIN)
$(BIN): mseed2sac.obj
link.exe /nologo /out:$(BIN) $(LIBS) mseed2sac.obj
.c.obj:
$(CC) /nologo $(CFLAGS) $(INCS) $(OPTS) /c $<
# Clean-up directives
clean:
-del a.out core *.o *.obj *% *~ $(BIN)
mseed2sac-2.2+ds1/src/fdzipstream.c 0000664 0000000 0000000 00000105142 13225706503 0017177 0 ustar 00root root 0000000 0000000 /***************************************************************************
* fdzipstream.c
*
* Create ZIP archives in streaming fashion, writing to a file
* descriptor. The output stream (file descriptor) does not need to
* be seekable and can be a pipe or a network socket. The entire
* archive contents does not need to be in memory at once.
*
* zlib is required for deflate compression: http://www.zlib.net/
*
* What this will do for you:
*
* - Create a ZIP archive in a streaming fashion, writing to an output
* stream (file descriptor, pipe, network socket) without seeking.
* - Compress the archive entries (using zlib). Support for the STORE
* and DEFLATE methods is included, others may be implemented through
* callback functions.
* - Add ZIP64 structures as needed to support large (>4GB) archives.
* - Simple creation of ZIP archives even if not streaming.
*
* What this will NOT do for you:
*
* - Open/close files or sockets.
* - Support advanced ZIP archive features (e.g. file attributes, encryption).
* - Allow archiving of individual files/entries larger than 4GB, the total
* of all files can be larger than 4GB but not individual entries.
*
* ZIP archive file/entry modifiation times are stored in UTC.
*
* Usage pattern
*
* Creating a ZIP archive when entire files/entries are in memory:
* zs_init ()
* for each entry:
* zs_writeentry ()
* zs_finish ()
* zs_free ()
*
* Creating a ZIP archive when files/entries are chunked:
* zs_init ()
* for each entry:
* zs_entrybegin ()
* for each chunk of entry:
* zs_entrydata()
* zs_entryend()
* zs_finish ()
* zs_free ()
*
****
* To use archive entry compression methods other than the included
* STORE and DEFLATE methods you must create and register callback
* funtions as follows:
*
* int32_t init (ZIPstream *zstream, ZIPentry *zentry)
*
* This optional function is called at the beginning of each entry.
* Return: 0 on success and non-zero on error.
*
* int32_t process (ZIPstream *zstream, ZIPentry *zentry,
* uint8_t *entry, int64_t entrySize, int64_t *entryConsumed,
* uint8_t* writeBuffer, int64_t writeBufferSize)
*
* This required function is called to process entry content data.
* Data to write into the archive should be returned in writeBuffer.
* When entry is NULL internal buffers should be flushed.
* Return: Count of bytes ready in writeBuffer, 0 on completion and <0 on error
*
* int32_t finish (ZIPstream *zstream, ZIPentry *zentry)
*
* This optional function is called at the end of each entry.
* Return: 0 on success and non-zero on error.
*
* These three functions must be registered, through zs_registermethod(),
* with any ZIPstream that will use them.
****
* LICENSE
*
* Copyright 2015 CTrabant
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Modified 2017.1.17
***************************************************************************/
/* Allow this code to be skipped by declaring NOFDZIP */
#ifndef NOFDZIP
#define FDZIPVERSION 2.1
#include
#include
#include
#include
#include
#include
#include
#include
#include "fdzipstream.h"
#define BIT_SET(a,b) ((a) |= (1<<(b)))
static int64_t zs_writedata ( ZIPstream *zstream, uint8_t *writeBuffer, int64_t writeBufferSize );
static uint32_t zs_datetime_unixtodos ( time_t t );
static void zs_packunit16 (ZIPstream *ZS, int *O, uint16_t V);
static void zs_packunit32 (ZIPstream *ZS, int *O, uint32_t V);
static void zs_packunit64 (ZIPstream *ZS, int *O, uint64_t V);
/***************************************************************************
* zs_store_process:
*
* The process() callback for the STORE method.
*
* @return number of bytes ready for writing in writeBuffer or <0 on error.
***************************************************************************/
static int32_t
zs_store_process ( ZIPstream *zstream, ZIPentry *zentry,
uint8_t *entry, int64_t entrySize, int64_t *entryConsumed,
uint8_t *writeBuffer, int64_t writeBufferSize )
{
if ( ! entry || entrySize <= 0 )
return 0;
if ( entrySize < writeBufferSize )
{
writeBufferSize = entrySize;
}
memcpy ( writeBuffer, entry, writeBufferSize );
if ( entryConsumed )
{
*entryConsumed = writeBufferSize;
}
return writeBufferSize;
} /* End of zs_store_process() */
/***************************************************************************
* zs_deflate_init:
*
* Initialization for the deflate method.
*
* @return 0 on sucess and non-zero on error.
***************************************************************************/
static int32_t
zs_deflate_init ( ZIPstream *zstream, ZIPentry *zentry )
{
z_stream *zlstream;
/* Allocate ZLIB stream entry and store at private method pointer */
zlstream = (z_stream *) calloc (1, sizeof(z_stream));
if ( ! zlstream )
{
fprintf (stderr, "Cannot allocate memory for z_stream\n");
return -1;
}
zentry->methoddata = zlstream;
/* Allocate deflate zlib stream state & initialize */
zlstream->zalloc = Z_NULL;
zlstream->zfree = Z_NULL;
zlstream->opaque = Z_NULL;
zlstream->total_in = 0;
zlstream->total_out = 0;
zlstream->data_type = Z_BINARY;
if ( deflateInit2 (zlstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK )
{
fprintf (stderr, "zs_deflate_init: Error with deflateInit2()\n");
return -1;
}
return 0;
}
/***************************************************************************
* zs_deflate_process:
*
* Process data for deflate method.
*
* @return number of bytes ready for writing in writeBuffer or <0 on error.
***************************************************************************/
static int32_t
zs_deflate_process( ZIPstream *zstream, ZIPentry *zentry,
uint8_t *entry, int64_t entrySize, int64_t *entryConsumed,
uint8_t* writeBuffer, int64_t writeBufferSize )
{
z_stream *zlstream;
int flush;
int rv;
if ( ! zstream || ! zentry )
return -1;
zlstream = zentry->methoddata;
if ( ! zlstream )
return -1;
zlstream->next_in = entry;
zlstream->avail_in = ( entry ) ? entrySize : 0;
zlstream->next_out = writeBuffer;
zlstream->avail_out = writeBufferSize;
flush = ( entry ) ? Z_NO_FLUSH : Z_FINISH;
rv = deflate ( zlstream, flush );
if ( ! (entry && rv == Z_OK) &&
! (!entry && rv == Z_STREAM_END) )
{
fprintf (stderr, "zs_deflate_process: Error with deflate():\n");
if ( rv == Z_BUF_ERROR )
fprintf (stderr, " ZLIB: Z_BUF_ERROR, No progress is possible; either avail_in or avail_out was zero\n");
else if ( rv == Z_MEM_ERROR )
fprintf (stderr, " ZLIB: Z_MEM_ERROR, Insufficient memory\n");
else if ( rv == Z_STREAM_ERROR )
fprintf (stderr, " ZLIB: Z_STREAM_ERROR, The stream state is inconsistent or stream was NULL\n");
else
fprintf (stderr, " ZLIB: deflated returned %d\n", rv);
return -1;
}
if ( entry && entryConsumed )
{
*entryConsumed = entrySize - zlstream->avail_in;
}
/* Return number of bytes ready in writeBuffer */
return (writeBufferSize - zlstream->avail_out);
}
/***************************************************************************
* zs_deflate_finish:
*
* Closeout for deflate method.
*
* @return 0 on success and non-zero on error.
***************************************************************************/
static int32_t
zs_deflate_finish ( ZIPstream *zstream, ZIPentry *zentry )
{
z_stream *zlstream = zentry->methoddata;
int rv;
int rc = 0;
rv = deflateEnd (zlstream);
if ( rv == Z_DATA_ERROR )
{
fprintf (stderr, "zs_deflate_finish: Deflate ended, but output buffers not flushed!\n");
rc = -1;
}
else if ( rv == Z_STREAM_ERROR )
{
fprintf (stderr, "zs:deflate_finish: deflateEnd() returned error.\n");
rc = -1;
}
free (zlstream);
return rc;
}
/***************************************************************************
* zs_registermethod:
*
* Initialize a new ZIPmethod entry and add it to the method list for
* the supplied ZIPstream.
*
* Each method requires an ID, mind that the ZIP APPNOTE defines some
* specific IDs already. Each method is also required to provide
* three functions:
*
* init() : Initialization to start an entry, optional.
* process() : Process new data and/or flush to finalize an entry, required.
* finish() : Finalize an entry, cleanup, optional.
*
* Optional function pointers should NULL if no action is needed.
*
* @return a pointer to a ZIPmethod struct on success or NULL on error.
***************************************************************************/
ZIPmethod *
zs_registermethod ( ZIPstream *zs, int32_t methodID,
int32_t (*init)( ZIPstream*, ZIPentry* ),
int32_t (*process)( ZIPstream*, ZIPentry*,
uint8_t*, int64_t, int64_t*,
uint8_t*, int64_t ),
int32_t (*finish)( ZIPstream*, ZIPentry* )
)
{
ZIPmethod *method = zs->firstMethod;
/* Require a process() callback for the method */
if ( ! process )
{
fprintf (stderr, "Compression method (%d) must provide a process() callback\n",
methodID);
return NULL;
}
/* Search for existing method */
while ( method )
{
if ( method->ID == methodID )
{
fprintf (stderr, "Compression method (%d) already registered\n",
methodID);
return NULL;
}
method = method->next;
}
/* Allocate and initialize new method */
method = (ZIPmethod *) calloc (1, sizeof(ZIPmethod));
if ( method == NULL )
{
fprintf (stderr, "Cannot allocate memory for method\n");
return NULL;
}
method->ID = methodID;
method->init = init;
method->process = process;
method->finish = finish;
/* Add new method to ZIPstream list */
method->next = zs->firstMethod;
zs->firstMethod = method;
return method;
} /* End of zs_registermethod() */
/***************************************************************************
* zs_init:
*
* Initialize and return an ZIPstream struct. If a pointer to an
* existing ZIPstream is supplied it will be re-initizlied, otherwise
* memory will be allocated.
*
* @return a pointer to a ZIPstream struct on success or NULL on error.
***************************************************************************/
ZIPstream *
zs_init ( int fd, ZIPstream *zs )
{
ZIPentry *zentry, *zefree;
ZIPmethod *method, *mfree;
if ( ! zs )
{
zs = (ZIPstream *) malloc (sizeof(ZIPstream));
}
else
{
zentry = zs->FirstEntry;
while ( zentry )
{
zefree = zentry;
zentry = zentry->next;
free (zefree);
}
method = zs->firstMethod;
while ( method )
{
mfree = method;
method = method->next;
free (mfree);
}
}
if ( zs == NULL )
{
fprintf (stderr, "zs_init: Cannot allocate memory for ZIPstream\n");
return NULL;
}
memset (zs, 0, sizeof (ZIPstream));
zs->fd = fd;
/* Register the included ZS_STORE and ZS_DEFLATE compression methods */
if ( ! zs_registermethod ( zs, ZS_STORE,
NULL,
zs_store_process,
NULL ) )
{
free (zs);
return NULL;
}
if ( ! zs_registermethod ( zs, ZS_DEFLATE,
zs_deflate_init,
zs_deflate_process,
zs_deflate_finish ) )
{
free (zs);
return NULL;
}
return zs;
} /* End of zs_init() */
/***************************************************************************
* zs_free:
*
* Free all memory associated with a ZIPstream including all ZIPentry
* structures.
***************************************************************************/
void
zs_free ( ZIPstream *zs )
{
ZIPentry *zentry, *zefree;
ZIPmethod *method, *mfree;
if ( ! zs )
return;
zentry = zs->FirstEntry;
while ( zentry )
{
zefree = zentry;
zentry = zentry->next;
free (zefree);
}
method = zs->firstMethod;
while ( method )
{
mfree = method;
method = method->next;
free (mfree);
}
free (zs);
} /* End of zs_free() */
/***************************************************************************
* zs_writeentry:
*
* Write ZIP archive entry contained in a memory buffer using the
* specified compression methodID.
*
* The methodID argument specifies the compression methodID to be used
* for this entry. Included methods are:
* Z_STORE - no compression
* Z_DEFLATE - deflate compression
*
* The entry modified time (modtime) is stored in UTC.
*
* If specified, writestatus will be set to the output of write() when
* a write error occurs, otherwise it will be set to 0.
*
* @return pointer to ZIPentry on success and NULL on error.
***************************************************************************/
ZIPentry *
zs_writeentry ( ZIPstream *zstream, uint8_t *entry, int64_t entrySize,
char *name, time_t modtime, int methodID, ssize_t *writestatus )
{
ZIPentry *zentry = NULL;
if ( writestatus )
*writestatus = 0;
if ( ! zstream )
return NULL;
if ( entrySize > 0xFFFFFFFF )
{
fprintf (stderr, "zs_writeentry(%s): Individual entries cannot exceed %lld bytes\n",
(name) ? name : "", (long long) 0xFFFFFFFF);
return NULL;
}
/* Begin entry */
if ( ! (zentry = zs_entrybegin ( zstream, name, modtime, methodID, writestatus )) )
{
return NULL;
}
/* Process entry data and flush */
if ( ! zs_entrydata (zstream, zentry, entry, entrySize, writestatus) )
{
return NULL;
}
/* End entry */
if ( ! zs_entryend (zstream, zentry, writestatus) )
{
return NULL;
}
return zentry;
} /* End of zs_writeentry() */
/***************************************************************************
* zs_entrybegin:
*
* Begin a streaming entry by writing a Local File Header to the
* output stream. The modtime argument sets the modification time
* stamp for the entry.
*
* The methodID argument specifies the compression method to be used
* for this entry. Included methods are:
* Z_STORE - no compression
* Z_DEFLATE - deflate compression
*
* The entry modified time (modtime) is stored in UTC.
*
* If specified, writestatus will be set to the output of write() when
* a write error occurs, otherwise it will be set to 0.
*
* @return pointer to ZIPentry on success and NULL on error.
***************************************************************************/
ZIPentry *
zs_entrybegin ( ZIPstream *zstream, char *name, time_t modtime, int methodID,
ssize_t *writestatus )
{
ZIPentry *zentry;
ZIPmethod *method;
int64_t lwritestatus;
int32_t packed;
uint32_t u32;
if ( writestatus )
*writestatus = 0;
if ( ! zstream || ! name )
return NULL;
/* Search for method ID */
method = zstream->firstMethod;
while ( method )
{
if ( method->ID == methodID )
break;
method = method->next;
}
if ( ! method )
{
fprintf (stderr, "Cannot find method ID %d\n", methodID);
return NULL;
}
/* Allocate and initialize new entry */
zentry = (ZIPentry *) calloc (1, sizeof(ZIPentry));
if ( zentry == NULL )
{
fprintf (stderr, "Cannot allocate memory for entry\n");
return NULL;
}
zentry->ZipVersion = 20; /* Default version for extraction (2.0) */
zentry->GeneralFlag = 0;
u32 = zs_datetime_unixtodos (modtime);
zentry->CompressionMethod = methodID;
zentry->DOSDate = (uint16_t) (u32 >> 16);
zentry->DOSTime = (uint16_t) (u32 & 0xFFFF);
zentry->CRC32 = crc32 (0L, Z_NULL, 0);
zentry->CompressedSize = 0;
zentry->UncompressedSize = 0;
zentry->LocalHeaderOffset = zstream->WriteOffset;
strncpy (zentry->Name, (name)?name:"", ZENTRY_NAME_LENGTH - 1);
zentry->NameLength = strlen (zentry->Name);
zentry->method = method;
zentry->methoddata = NULL;
/* Add new entry to stream list */
if ( ! zstream->FirstEntry )
{
zstream->FirstEntry = zentry;
zstream->LastEntry = zentry;
}
else
{
zstream->LastEntry->next = zentry;
zstream->LastEntry = zentry;
}
zstream->EntryCount++;
/* Set bit to denote streaming */
BIT_SET (zentry->GeneralFlag, 3);
/* Method initialization callback */
if ( zentry->method->init &&
zentry->method->init (zstream, zentry) )
{
fprintf (stderr, "Error with method (%d) init callback\n",
zentry->method->ID);
return NULL;
}
/* Write the Local File Header, with zero'd CRC and sizes (for streaming) */
packed = 0;
zs_packunit32 (zstream, &packed, LOCALHEADERSIG); /* Data Description signature */
zs_packunit16 (zstream, &packed, zentry->ZipVersion);
zs_packunit16 (zstream, &packed, zentry->GeneralFlag);
zs_packunit16 (zstream, &packed, zentry->CompressionMethod);
zs_packunit16 (zstream, &packed, zentry->DOSTime); /* DOS file modification time */
zs_packunit16 (zstream, &packed, zentry->DOSDate); /* DOS file modification date */
zs_packunit32 (zstream, &packed, zentry->CRC32); /* CRC-32 value of entry */
zs_packunit32 (zstream, &packed, zentry->CompressedSize); /* Compressed entry size */
zs_packunit32 (zstream, &packed, zentry->UncompressedSize); /* Uncompressed entry size */
zs_packunit16 (zstream, &packed, zentry->NameLength); /* File/entry name length */
zs_packunit16 (zstream, &packed, 0); /* Extra field length */
/* File/entry name */
memcpy (zstream->buffer+packed, zentry->Name, zentry->NameLength); packed += zentry->NameLength;
lwritestatus = zs_writedata (zstream, zstream->buffer, packed);
if ( lwritestatus != packed )
{
fprintf (stderr, "Error writing ZIP local header: %s\n", strerror(errno));
if ( writestatus )
*writestatus = (ssize_t)lwritestatus;
return NULL;
}
return zentry;
} /* End of zs_entrybegin() */
/***************************************************************************
* zs_entrydata:
*
* Write a chunk of entry data, of size entrySize, to the output
* stream according to the parameters already set for the stream and
* entry.
*
* When entry is NULL this signals a flush of any internal buffers.
* No further data is expected after this.
*
* If specified, writestatus will be set to the output of write() when
* a write error occurs, otherwise it will be set to 0.
*
* @return pointer to ZIPentry on success and NULL on error.
***************************************************************************/
ZIPentry *
zs_entrydata ( ZIPstream *zstream, ZIPentry *zentry, uint8_t *entry,
int64_t entrySize, ssize_t *writestatus )
{
int32_t writeSize = 0;
int64_t lwritestatus;
int64_t consumed = 0;
int64_t remaining = 0;
if ( writestatus )
*writestatus = 0;
if ( ! zstream || ! zentry )
return NULL;
if ( entry )
{
/* Calculate, or continue calculation of, CRC32 */
zentry->CRC32 = crc32 (zentry->CRC32, (uint8_t *)entry, entrySize);
remaining = entrySize;
}
/* Call method callback for processing data until all input is consumed */
while ( (writeSize = zentry->method->process( zstream, zentry,
entry, remaining, &consumed,
zstream->buffer,
sizeof(zstream->buffer)) ) > 0 )
{
/* Write processed data to stream */
lwritestatus = zs_writedata (zstream, zstream->buffer, writeSize);
if ( lwritestatus != writeSize )
{
fprintf (stderr, "zs_entrydata: Error writing ZIP entry data (%d): %s\n",
zstream->fd, strerror(errno));
if ( writestatus )
*writestatus = (ssize_t)lwritestatus;
return NULL;
}
zentry->CompressedSize += writeSize;
if ( entry )
{
entry += consumed;
remaining -= consumed;
if ( remaining <= 0 )
break;
}
}
if ( writeSize < 0 )
{
fprintf (stderr, "zs_entrydata: Process callback failed\n");
return NULL;
}
if ( entry )
{
zentry->UncompressedSize += entrySize;
}
return zentry;
} /* End of zs_entrydata() */
/***************************************************************************
* zs_entryend:
*
* End a streaming entry by writing a Data Description record to
* output stream.
*
* If specified, writestatus will be set to the output of write() when
* a write error occurs, otherwise it will be set to 0.
*
* @return pointer to ZIPentry on success and NULL on error.
***************************************************************************/
ZIPentry *
zs_entryend ( ZIPstream *zstream, ZIPentry *zentry, ssize_t *writestatus)
{
int64_t lwritestatus;
int32_t packed;
if ( writestatus )
*writestatus = 0;
if ( ! zstream || ! zentry )
return NULL;
/* Flush the entry */
if ( ! zs_entrydata (zstream, zentry, NULL, 0, writestatus) )
{
fprintf (stderr, "Error flushing entry (writestatus: %p)\n",
writestatus);
return NULL;
}
/* Method finish callback */
if ( zentry->method->finish &&
zentry->method->finish (zstream, zentry) )
{
fprintf (stderr, "Error with method (%d) finish callback\n",
zentry->method->ID);
return NULL;
}
/* Write Data Description */
packed = 0;
zs_packunit32 (zstream, &packed, DATADESCRIPTIONSIG); /* Data Description signature */
zs_packunit32 (zstream, &packed, zentry->CRC32); /* CRC-32 value of entry */
zs_packunit32 (zstream, &packed, zentry->CompressedSize); /* Compressed entry size */
zs_packunit32 (zstream, &packed, zentry->UncompressedSize); /* Uncompressed entry size */
lwritestatus = zs_writedata (zstream, zstream->buffer, packed);
if ( lwritestatus != packed )
{
fprintf (stderr, "Error writing streaming ZIP data description: %s\n", strerror(errno));
if ( writestatus )
*writestatus = (ssize_t)lwritestatus;
return NULL;
}
return zentry;
} /* End of zs_entryend() */
/***************************************************************************
* zs_finish:
*
* Write end of ZIP archive structures (Central Directory, etc.).
*
* ZIP64 structures will be added to the Central Directory when the
* total length of the archive exceeds 0xFFFFFFFF bytes.
*
* If specified, writestatus will be set to the output of write() when
* a write error occurs, otherwise it will be set to 0.
*
* @return 0 on success and non-zero on error.
***************************************************************************/
int
zs_finish ( ZIPstream *zstream, ssize_t *writestatus )
{
ZIPentry *zentry;
int64_t lwritestatus;
int packed;
uint64_t cdsize;
uint64_t zip64endrecord;
int zip64 = 0;
if ( writestatus )
*writestatus = 0;
if ( ! zstream )
return -1;
/* Store offset of Central Directory */
zstream->CentralDirectoryOffset = zstream->WriteOffset;
zentry = zstream->FirstEntry;
while ( zentry )
{
zip64 = ( zentry->LocalHeaderOffset > 0xFFFFFFFF ) ? 1 : 0;
/* Write Central Directory Header, packing into write buffer and swapped to little-endian order */
packed = 0;
zs_packunit32 (zstream, &packed, CENTRALHEADERSIG); /* Central File Header signature */
zs_packunit16 (zstream, &packed, 0); /* Version made by */
zs_packunit16 (zstream, &packed, zentry->ZipVersion); /* Version needed to extract */
zs_packunit16 (zstream, &packed, zentry->GeneralFlag); /* General purpose bit flag */
zs_packunit16 (zstream, &packed, zentry->CompressionMethod); /* Compression method */
zs_packunit16 (zstream, &packed, zentry->DOSTime); /* DOS file modification time */
zs_packunit16 (zstream, &packed, zentry->DOSDate); /* DOS file modification date */
zs_packunit32 (zstream, &packed, zentry->CRC32); /* CRC-32 value of entry */
zs_packunit32 (zstream, &packed, zentry->CompressedSize); /* Compressed entry size */
zs_packunit32 (zstream, &packed, zentry->UncompressedSize); /* Uncompressed entry size */
zs_packunit16 (zstream, &packed, zentry->NameLength); /* File/entry name length */
zs_packunit16 (zstream, &packed, ( zip64 ) ? 12 : 0 ); /* Extra field length, switch for ZIP64 */
zs_packunit16 (zstream, &packed, 0); /* File/entry comment length */
zs_packunit16 (zstream, &packed, 0); /* Disk number start */
zs_packunit16 (zstream, &packed, 0); /* Internal file attributes */
zs_packunit32 (zstream, &packed, 0); /* External file attributes */
zs_packunit32 (zstream, &packed, ( zip64 ) ?
0xFFFFFFFF : zentry->LocalHeaderOffset); /* Relative offset of Local Header */
/* File/entry name */
memcpy (zstream->buffer+packed, zentry->Name, zentry->NameLength);
packed += zentry->NameLength;
if ( zip64 ) /* ZIP64 Extra Field */
{
zs_packunit16 (zstream, &packed, 1); /* Extra field ID, 1 = ZIP64 */
zs_packunit16 (zstream, &packed, 8); /* Extra field data length */
zs_packunit64 (zstream, &packed, zentry->LocalHeaderOffset); /* Offset to Local Header */
}
lwritestatus = zs_writedata (zstream, zstream->buffer, packed);
if ( lwritestatus != packed )
{
fprintf (stderr, "Error writing ZIP central directory header: %s\n", strerror(errno));
if ( writestatus )
*writestatus = (ssize_t)lwritestatus;
return -1;
}
zentry = zentry->next;
}
/* Calculate size of Central Directory */
cdsize = zstream->WriteOffset - zstream->CentralDirectoryOffset;
/* Add ZIP64 structures if offset to Central Directory is beyond limit */
if ( zstream->CentralDirectoryOffset > 0xFFFFFFFF )
{
/* Note offset of ZIP64 End of Central Directory Record */
zip64endrecord = zstream->WriteOffset;
/* Write ZIP64 End of Central Directory Record, packing into write buffer and swapped to little-endian order */
packed = 0;
zs_packunit32 (zstream, &packed, ZIP64ENDRECORDSIG); /* ZIP64 End of Central Dir record */
zs_packunit64 (zstream, &packed, 44); /* Size of this record after this field */
zs_packunit16 (zstream, &packed, 30); /* Version made by */
zs_packunit16 (zstream, &packed, 45); /* Version needed to extract */
zs_packunit32 (zstream, &packed, 0); /* Number of this disk */
zs_packunit32 (zstream, &packed, 0); /* Disk with start of the CD */
zs_packunit64 (zstream, &packed, zstream->EntryCount); /* Number of CD entries on this disk */
zs_packunit64 (zstream, &packed, zstream->EntryCount); /* Total number of CD entries */
zs_packunit64 (zstream, &packed, cdsize); /* Size of Central Directory */
zs_packunit64 (zstream, &packed, zstream->CentralDirectoryOffset); /* Offset to Central Directory */
lwritestatus = zs_writedata (zstream, zstream->buffer, packed);
if ( lwritestatus != packed )
{
fprintf (stderr, "Error writing ZIP64 end of central directory record: %s\n", strerror(errno));
if ( writestatus )
*writestatus = (ssize_t)lwritestatus;
return -1;
}
/* Write ZIP64 End of Central Directory Locator, packing into write buffer and swapped to little-endian order */
packed = 0;
zs_packunit32 (zstream, &packed, ZIP64ENDLOCATORSIG); /* ZIP64 End of Central Dir Locator */
zs_packunit32 (zstream, &packed, 0); /* Number of disk w/ ZIP64 End of CD */
zs_packunit64 (zstream, &packed, zip64endrecord); /* Offset to ZIP64 End of CD */
zs_packunit32 (zstream, &packed, 1); /* Total number of disks */
lwritestatus = zs_writedata (zstream, zstream->buffer, packed);
if ( lwritestatus != packed )
{
fprintf (stderr, "Error writing ZIP64 end of central directory locator: %s\n", strerror(errno));
if ( writestatus )
*writestatus = (ssize_t)lwritestatus;
return -1;
}
}
/* Write End of Central Directory Record, packing into write buffer and swapped to little-endian order */
packed = 0;
zs_packunit32 (zstream, &packed, ENDHEADERSIG); /* End of Central Dir signature */
zs_packunit16 (zstream, &packed, 0); /* Number of this disk */
zs_packunit16 (zstream, &packed, 0); /* Number of disk with CD */
zs_packunit16 (zstream, &packed, zstream->EntryCount); /* Number of entries in CD this disk */
zs_packunit16 (zstream, &packed, zstream->EntryCount); /* Number of entries in CD */
zs_packunit32 (zstream, &packed, cdsize); /* Size of Central Directory */
zs_packunit32 (zstream, &packed, (zstream->CentralDirectoryOffset > 0xFFFFFFFF) ?
0xFFFFFFFF : zstream->CentralDirectoryOffset); /* Offset to start of CD */
zs_packunit16 (zstream, &packed, 0); /* ZIP file comment length */
lwritestatus = zs_writedata (zstream, zstream->buffer, packed);
if ( lwritestatus != packed )
{
fprintf (stderr, "Error writing end of central directory record: %s\n", strerror(errno));
if ( writestatus )
*writestatus = (ssize_t)lwritestatus;
return -1;
}
return 0;
} /* End of zs_finish() */
/***************************************************************************
* zs_writedata:
*
* Write data to output descriptor in blocks of ZS_WRITE_SIZE bytes.
*
* The ZIPstream.WriteOffset value will be incremented accordingly.
*
* @return number of bytes written on success and return value of write() on error.
***************************************************************************/
static int64_t
zs_writedata ( ZIPstream *zstream, uint8_t *writeBuffer, int64_t writeBufferSize )
{
ssize_t lwritestatus;
size_t writeLength;
int64_t written;
if ( ! zstream || ! writeBuffer )
return 0;
/* Write blocks of ZS_WRITE_SIZE until done */
written = 0;
while ( written < writeBufferSize )
{
writeLength = ( (writeBufferSize - written) > ZS_WRITE_SIZE ) ?
ZS_WRITE_SIZE : (writeBufferSize - written);
lwritestatus = write (zstream->fd, writeBuffer+written, writeLength);
if ( lwritestatus <= 0 )
{
return lwritestatus;
}
zstream->WriteOffset += lwritestatus;
written += lwritestatus;
}
return written;
} /* End of zs_writedata() */
/* DOS time start date is January 1, 1980 */
#define DOSTIME_STARTDATE 0x00210000L
/***************************************************************************
* zs_datetime_unixtodos:
*
* Convert Unix time_t to 4 byte DOS date and time.
*
* Routine adapted from sources:
* Copyright (C) 2006 Michael Liebscher
*
* @return converted 4-byte quantity on success and 0 on error.
***************************************************************************/
static uint32_t
zs_datetime_unixtodos ( time_t t )
{
struct tm s;
if ( gmtime_r (&t, &s) == NULL )
return 0;
s.tm_year += 1900;
s.tm_mon += 1;
return ( ((s.tm_year) < 1980) ? DOSTIME_STARTDATE :
(((uint32_t)(s.tm_year) - 1980) << 25) |
((uint32_t)(s.tm_mon) << 21) |
((uint32_t)(s.tm_mday) << 16) |
((uint32_t)(s.tm_hour) << 11) |
((uint32_t)(s.tm_min) << 5) |
((uint32_t)(s.tm_sec) >> 1) );
}
/***************************************************************************
* Byte swapping routine:
*
* Functions for generalized, in-place byte swapping from host order
* to little-endian. A run-time test of byte order is conducted on
* the first usage and a static variable is used to store the result
* for later use.
*
* The byte-swapping requires memory-aligned quantities.
*
***************************************************************************/
static void
zs_htolx ( void *data, int size )
{
static int le = -1;
int16_t host = 1;
uint16_t *data2;
uint32_t *data4;
uint32_t h0, h1;
/* Determine byte order, test for little-endianness */
if ( le < 0 )
{
le = (*((int8_t *)(&host)));
}
/* Swap bytes if not little-endian, requires memory-aligned quantities */
if ( le == 0 )
{
switch ( size )
{
case 2:
data2 = (uint16_t *) data;
*data2=(((*data2>>8)&0xff) | ((*data2&0xff)<<8));
break;
case 4:
data4 = (uint32_t *) data;
*data4=(((*data4>>24)&0xff) | ((*data4&0xff)<<24) |
((*data4>>8)&0xff00) | ((*data4&0xff00)<<8));
break;
case 8:
data4 = (uint32_t *) data;
h0 = data4[0];
h0 = (((h0>>24)&0xff) | ((h0&0xff)<<24) |
((h0>>8)&0xff00) | ((h0&0xff00)<<8));
h1 = data4[1];
h1 = (((h1>>24)&0xff) | ((h1&0xff)<<24) |
((h1>>8)&0xff00) | ((h1&0xff00)<<8));
data4[0] = h1;
data4[1] = h0;
break;
}
}
}
/***************************************************************************
*
* Helper functions to write little-endian integer values to a
* specified offset in the ZIPstream buffer and increment offset.
*
***************************************************************************/
static void zs_packunit16 (ZIPstream *ZS, int *O, uint16_t V)
{
memcpy (ZS->buffer+*O, &V, 2);
zs_htolx(ZS->buffer+*O, 2);
*O += 2;
}
static void zs_packunit32 (ZIPstream *ZS, int *O, uint32_t V)
{
memcpy (ZS->buffer+*O, &V, 4);
zs_htolx(ZS->buffer+*O, 4);
*O += 4;
}
static void zs_packunit64 (ZIPstream *ZS, int *O, uint64_t V)
{
memcpy (ZS->buffer+*O, &V, 8);
zs_htolx(ZS->buffer+*O, 8);
*O += 8;
}
#endif /* NOFDZIP */
mseed2sac-2.2+ds1/src/fdzipstream.h 0000664 0000000 0000000 00000007254 13225706503 0017211 0 ustar 00root root 0000000 0000000
/* Allow this code to be skipped by declaring NOFDZIP */
#ifndef NOFDZIP
#ifndef FDZIPSTREAM_H
#define FDZIPSTREAM_H
#include
#include
#include
#ifdef __cplusplus
extern "C" {
#endif
#ifndef DEF_MEM_LEVEL
# if MAX_MEM_LEVEL >= 8
# define DEF_MEM_LEVEL 8
# else
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
# endif
#endif
/* ZIP record type signatures */
#define LOCALHEADERSIG (0x04034b50)
#define DATADESCRIPTIONSIG (0x08074b50)
#define CENTRALHEADERSIG (0x02014b50)
#define ZIP64ENDRECORDSIG (0x06064b50)
#define ZIP64ENDLOCATORSIG (0x07064b50)
#define ENDHEADERSIG (0x06054b50)
/* Compression methods, match ZIP specification */
#define ZS_STORE 0
#define ZS_DEFLATE 8
/* Maximum single size to write(), 1 MiB */
#define ZS_WRITE_SIZE 1048576
/* Multi-use stream buffer, 256 KiB */
#define ZS_BUFFER_SIZE 262144
/* Maximum length of file/entry name including NULL terminator */
#define ZENTRY_NAME_LENGTH 256
/* ZIP archive entry */
typedef struct zipentry_s
{
uint16_t ZipVersion;
uint16_t GeneralFlag;
uint16_t CompressionMethod;
uint16_t DOSDate;
uint16_t DOSTime;
uint32_t CRC32;
uint64_t CompressedSize;
uint64_t UncompressedSize;
uint64_t LocalHeaderOffset;
uint16_t NameLength;
char Name[ZENTRY_NAME_LENGTH];
struct zipmethod_s *method; /* Pointer to compression method entry */
void *methoddata; /* A private pointer for method data */
struct zipentry_s *next;
} ZIPentry;
/* ZIP output stream managment */
typedef struct zipstream_s
{
int fd;
int64_t WriteOffset;
int64_t CentralDirectoryOffset;
int32_t EntryCount;
struct zipentry_s *FirstEntry;
struct zipentry_s *LastEntry;
struct zipmethod_s *firstMethod;
uint8_t buffer[ZS_BUFFER_SIZE];
} ZIPstream;
/* List of ZIP method (compression) implementations */
typedef struct zipmethod_s
{
int32_t ID;
int32_t (*init)( ZIPstream *zstream, ZIPentry *zentry );
int32_t (*process)( ZIPstream *zstream, ZIPentry *zentry,
uint8_t *entry, int64_t entrySize, int64_t *entryConsumed,
uint8_t* writeBuffer, int64_t writeBufferSize );
int32_t (*finish)( ZIPstream *zstream, ZIPentry *zentry );
struct zipmethod_s* next;
} ZIPmethod;
extern ZIPmethod * zs_registermethod ( ZIPstream *zs, int32_t methodID,
int32_t (*init)( ZIPstream*, ZIPentry* ),
int32_t (*process)( ZIPstream*, ZIPentry*,
uint8_t*, int64_t, int64_t*,
uint8_t*, int64_t ),
int32_t (*finish)( ZIPstream*, ZIPentry* )
);
extern ZIPstream * zs_init ( int fd, ZIPstream *zs );
extern void zs_free ( ZIPstream *zs );
extern ZIPentry * zs_writeentry ( ZIPstream *zstream, uint8_t *entry, int64_t entrySize,
char *name, time_t modtime, int methodID, ssize_t *writestatus );
extern ZIPentry * zs_entrybegin ( ZIPstream *zstream, char *name,
time_t modtime, int methodID,
ssize_t *writestatus );
extern ZIPentry * zs_entrydata ( ZIPstream *zstream, ZIPentry *zentry,
uint8_t *entry, int64_t entrySize,
ssize_t *writestatus );
extern ZIPentry * zs_entryend ( ZIPstream *zstream, ZIPentry *zentry,
ssize_t *writestatus);
extern int zs_finish ( ZIPstream *zstream, ssize_t *writestatus );
#ifdef __cplusplus
}
#endif
#endif /* FDZIPSTREAM_H */
#endif /* NOFDZIP */
mseed2sac-2.2+ds1/src/mseed2sac.c 0000664 0000000 0000000 00000144753 13225706503 0016530 0 ustar 00root root 0000000 0000000 /***************************************************************************
* mseed2sac.c
*
* Convert miniSEED waveform data to SAC
*
* Written by Chad Trabant, IRIS Data Management Center
*
* modified 2017.272
***************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include "sacformat.h"
#ifndef NOFDZIP
#include "fdzipstream.h"
#endif
#if defined(WIN32) || defined(WIN64)
#include
#define access _access
#ifndef F_OK
#define F_OK 0
#endif
#endif
#define VERSION "2.2"
#define PACKAGE "mseed2sac"
/* An undefined value for double values */
#define DUNDEF -999.0
/* Maximum number of metadata fields per line */
#define MAXMETAFIELDS 17
/* Macro to test floating point number equality within 10 decimal places */
#define FLTEQUAL(F1, F2) (fabs (F1 - F2) < 1.0E-10 * (fabs (F1) + fabs (F2) + 1.0))
struct listnode
{
char *key;
char *data;
struct listnode *next;
};
struct metanode
{
char *metafields[MAXMETAFIELDS];
hptime_t starttime;
hptime_t endtime;
};
static int writesac (MSTrace *mst);
static int writebinarysac (struct SACHeader *sh, float *fdata, int npts, char *outfile);
static int writealphasac (struct SACHeader *sh, float *fdata, int npts, char *outfile);
static int swapsacheader (struct SACHeader *sh);
static int insertmetadata (struct SACHeader *sh, hptime_t sacstarttime);
static int delaz (double lat1, double lon1, double lat2, double lon2,
double *delta, double *dist, double *azimuth, double *backazimuth);
static int parameter_proc (int argcount, char **argvec);
static char *getoptval (int argcount, char **argvec, int argopt, int dasharg);
static int readlistfile (char *listfile);
static int addmetadata (char *metaline);
static int readmetadata (char *metafile);
static struct listnode *addnode (struct listnode **listroot, void *key, int keylen,
void *data, int datalen);
static void usage (int level);
static int verbose = 0;
static int reclen = -1;
static int overwrite = 0;
static int deriverate = 0;
static int indifile = 0;
static int indichannel = 0;
static int sacformat = 2;
static double latitude = DUNDEF;
static double longitude = DUNDEF;
static char *network = 0;
static char *station = 0;
static char *location = 0;
static char *channel = 0;
static hptime_t eventtime = 0;
static double eventlat = DUNDEF;
static double eventlon = DUNDEF;
static double eventdepth = DUNDEF;
static char *eventname = 0;
static char *zipfile = 0;
#ifndef NOFDZIP
static ZIPstream *zstream = 0;
static int zipmethod = -1;
#endif
struct listnode *filelist = 0; /* List of input files */
static Selections *selections = 0; /* List of data selections */
struct listnode *metadata = 0; /* List of stations and coordinates, etc. */
static int seedinc = 0; /* SEED component inclination flag */
int
main (int argc, char **argv)
{
MSTraceGroup *mstg = 0;
MSTrace *mst = 0;
MSRecord *msr = 0;
struct listnode *flp;
char srcname[50];
char prevsrcname[50];
char starttime[50];
hptime_t recendtime;
int retcode;
int64_t totalrecs = 0;
int64_t totalsamps = 0;
int totalfiles = 0;
#ifndef NOFDZIP
FILE *zipfp;
int zipfd;
ssize_t writestatus = 0;
#endif /* NOFDZIP */
/* Process given parameters (command line and parameter file) */
if (parameter_proc (argc, argv) < 0)
return -1;
/* Init MSTraceGroup */
mstg = mst_initgroup (mstg);
#ifndef NOFDZIP
/* Open & intialize output ZIP archive if needed */
if (zipfile)
{
if (!strcmp (zipfile, "-")) /* Write ZIP to stdout */
{
if (verbose)
fprintf (stderr, "Writing ZIP archive to stdout\n");
zipfd = fileno (stdout);
}
else if ((zipfp = fopen (zipfile, "wb")) == NULL) /* Open output ZIP file */
{
fprintf (stderr, "Cannot open output file: %s (%s)\n",
zipfile, strerror (errno));
return -1;
}
else
{
if (verbose)
fprintf (stderr, "Writing ZIP archive to %s\n", zipfile);
zipfd = fileno (zipfp);
}
/* Initialize ZIP container */
if ((zstream = zs_init (zipfd, zstream)) == NULL)
{
fprintf (stderr, "Error in zs_init()\n");
return 1;
}
}
#endif /* NOFDZIP */
/* Read input miniSEED files into MSTraceGroup */
flp = filelist;
while (flp != 0)
{
if (verbose)
fprintf (stderr, "Reading %s\n", flp->data);
while ((retcode = ms_readmsr (&msr, flp->data, reclen, NULL, NULL,
1, 1, verbose - 1)) == MS_NOERROR)
{
/* Generate source name if needed for tests */
if (selections || indichannel)
{
msr_srcname (msr, srcname, 1);
}
/* Check if record is matched by selection */
if (selections)
{
recendtime = msr_endtime (msr);
if (!ms_matchselect (selections, srcname, msr->starttime, recendtime, NULL))
{
if (verbose >= 2)
{
ms_hptime2seedtimestr (msr->starttime, starttime, 1);
ms_log (1, "Skipping (selection) %s, %s\n", srcname, starttime);
}
continue;
}
}
/* If this is a new channel write previous data (if individual channel writing) */
if (indichannel)
{
if (totalrecs > 0)
{
if (strncmp (prevsrcname, srcname, sizeof (prevsrcname)))
{
mst = mstg->traces;
while (mst)
{
writesac (mst);
mst = mst->next;
}
mstg = mst_initgroup (mstg);
strncpy (prevsrcname, srcname, sizeof (prevsrcname));
}
}
else
{
strncpy (prevsrcname, srcname, sizeof (prevsrcname));
}
}
if (verbose >= 2)
msr_print (msr, verbose - 2);
mst_addmsrtogroup (mstg, msr, 1, -1.0, -1.0);
totalrecs++;
totalsamps += msr->samplecnt;
}
if (retcode != MS_ENDOFFILE)
fprintf (stderr, "Error reading %s: %s\n", flp->data, ms_errorstr (retcode));
/* Make sure everything is cleaned up */
ms_readmsr (&msr, NULL, 0, NULL, NULL, 0, 0, 0);
/* If processing each file individually, write SAC and reset */
if (indifile)
{
mst = mstg->traces;
while (mst)
{
writesac (mst);
mst = mst->next;
}
mstg = mst_initgroup (mstg);
}
totalfiles++;
flp = flp->next;
}
if (!indifile)
{
mst = mstg->traces;
while (mst)
{
writesac (mst);
mst = mst->next;
}
}
#ifndef NOFDZIP
/* Finish output ZIP archive if needed */
if (zipfile)
{
if (zs_finish (zstream, &writestatus))
{
fprintf (stderr, "Error finishing ZIP archive, write status: %lld\n",
(long long int)writestatus);
}
zs_free (zstream);
}
#endif /* NOFDZIP */
/* Make sure everything is cleaned up */
mst_freegroup (&mstg);
if (verbose)
fprintf (stderr, "Files: %d, Records: %lld, Samples: %lld\n",
totalfiles, (long long int)totalrecs, (long long int)totalsamps);
return 0;
} /* End of main() */
/***************************************************************************
* writesac:
*
* Write data buffer to output file as binary SAC.
*
* Returns the number of samples written or -1 on error.
***************************************************************************/
static int
writesac (MSTrace *mst)
{
struct SACHeader sh = NullSACHeader;
BTime btime;
char outfile[1024];
char baseoutfile[1024];
char *sacnetwork;
char *sacstation;
char *saclocation;
char *sacchannel;
float *fdata = 0;
double *ddata = 0;
int32_t *idata = 0;
hptime_t submsec;
int idx;
int rv;
if (!mst)
return -1;
if (mst->numsamples == 0 || mst->samprate == 0.0)
return 0;
/* Check reported versus derived sampling rates */
if (mst->starttime < mst->endtime)
{
hptime_t hptimeshift;
hptime_t hpdelta;
double samprate;
/* Calculate difference between end time of last miniSEED record and the end time
* as calculated based on the start time, reported sample rate and number of samples. */
hptimeshift = llabs (mst->endtime - mst->starttime - (hptime_t) ((mst->numsamples - 1) * HPTMODULUS / mst->samprate));
/* Calculate high-precision sample period using reported sample rate */
hpdelta = (hptime_t) ((mst->samprate) ? (HPTMODULUS / mst->samprate) : 0.0);
/* Test if time shift is beyond half a sample period */
if (hptimeshift > (hpdelta * 0.5))
{
/* Derive sample rate from start and end times and number of samples */
samprate = (double)(mst->numsamples - 1) * HPTMODULUS / (mst->endtime - mst->starttime);
if (deriverate)
{
if (verbose)
fprintf (stderr, "Using derived sample rate of %g over reported rate of %g\n",
samprate, mst->samprate);
mst->samprate = samprate;
}
else
{
fprintf (stderr, "[%s.%s.%s.%s] Reported sample rate different than derived rate (%g versus %g)\n",
mst->network, mst->station, mst->location, mst->channel,
mst->samprate, samprate);
fprintf (stderr, " Consider using the -dr option to use the sample rate derived from the series\n");
}
}
}
sacnetwork = (network) ? network : mst->network;
sacstation = (station) ? station : mst->station;
saclocation = (location) ? location : mst->location;
sacchannel = (channel) ? channel : mst->channel;
/* Insert dummy network code of XX if no network code is set */
if (!sacnetwork || *sacnetwork == '\0')
{
sacnetwork = "XX";
fprintf (stderr, "Warning: input data has no network code, inserting XX\n");
}
/* Set time-series source parameters */
if (sacnetwork)
if (*sacnetwork != '\0')
ms_strncpopen (sh.knetwk, sacnetwork, 8);
if (sacstation)
if (*sacstation != '\0')
ms_strncpopen (sh.kstnm, sacstation, 8);
if (saclocation)
if (*saclocation != '\0')
ms_strncpopen (sh.khole, saclocation, 8);
if (sacchannel)
if (*sacchannel != '\0')
ms_strncpopen (sh.kcmpnm, sacchannel, 8);
if (verbose)
fprintf (stderr, "Writing SAC for %.8s.%.8s.%.8s.%.8s\n",
sacnetwork, sacstation, saclocation, sacchannel);
/* Set misc. header variables */
sh.nvhdr = 6; /* Header version = 6 */
sh.leven = 1; /* Evenly spaced data */
sh.iftype = ITIME; /* Data is time-series */
/* Set sampling interval (seconds), sample count */
sh.delta = 1 / mst->samprate;
sh.npts = mst->numsamples;
/* Insert metadata */
if (metadata)
{
rv = insertmetadata (&sh, mst->starttime);
if (rv == -1)
fprintf (stderr, "Error inserting metadata for %.8s.%.8s.%.8s.%.8s\n",
sacnetwork, sacstation, saclocation, sacchannel);
else if (rv == 1)
fprintf (stderr, "No metadata found for %.8s.%.8s.%.8s.%.8s\n",
sacnetwork, sacstation, saclocation, sacchannel);
}
/* Set station coordinates specified on command line */
if (latitude != DUNDEF)
sh.stla = latitude;
if (longitude != DUNDEF)
sh.stlo = longitude;
/* Set event parameters */
if (eventtime)
sh.o = (float)MS_HPTIME2EPOCH ((eventtime - mst->starttime));
if (eventlat != DUNDEF)
sh.evla = (float)eventlat;
if (eventlon != DUNDEF)
sh.evlo = (float)eventlon;
if (eventdepth != DUNDEF)
sh.evdp = (float)eventdepth;
if (eventname)
ms_strncpopen (sh.kevnm, eventname, 16);
/* Calculate delta, distance and azimuths if both event and station coordiantes are known */
if (sh.evla != FUNDEF && sh.evlo != FUNDEF &&
sh.stla != FUNDEF && sh.stlo != FUNDEF)
{
double delta, dist, azimuth, backazimuth;
if (!delaz (sh.evla, sh.evlo, sh.stla, sh.stlo, &delta, &dist, &azimuth, &backazimuth))
{
sh.az = (float)azimuth;
sh.baz = (float)backazimuth;
sh.gcarc = (float)delta;
sh.dist = (float)dist;
if (verbose)
fprintf (stderr, "Inserting variables: AZ: %g, BAZ: %g, GCARC: %g, DIST: %g\n",
sh.az, sh.baz, sh.gcarc, sh.dist);
}
}
/* Set reference time */
ms_hptime2btime (mst->starttime, &btime);
sh.nzyear = btime.year;
sh.nzjday = btime.day;
sh.nzhour = btime.hour;
sh.nzmin = btime.min;
sh.nzsec = btime.sec;
sh.nzmsec = btime.fract / 10;
/* Determine any sub-millisecond portion of the start time in HP time */
submsec = (mst->starttime -
ms_time2hptime (sh.nzyear, sh.nzjday, sh.nzhour,
sh.nzmin, sh.nzsec, sh.nzmsec * 1000));
/* Set begin and end offsets from reference time for first and last sample,
* any sub-millisecond start time is stored in these offsets. */
sh.b = ((float)submsec / HPTMODULUS);
sh.e = (mst->numsamples - 1) * (1 / mst->samprate) + ((float)submsec / HPTMODULUS);
/* Convert data buffer to floats */
if (mst->sampletype == 'f')
{
fdata = (float *)mst->datasamples;
}
else if (mst->sampletype == 'i')
{
idata = (int32_t *)mst->datasamples;
fdata = (float *)malloc (mst->numsamples * sizeof (float));
if (fdata == NULL)
{
fprintf (stderr, "Error allocating memory\n");
return -1;
}
for (idx = 0; idx < mst->numsamples; idx++)
fdata[idx] = (float)idata[idx];
}
else if (mst->sampletype == 'd')
{
ddata = (double *)mst->datasamples;
fdata = (float *)malloc (mst->numsamples * sizeof (float));
if (fdata == NULL)
{
fprintf (stderr, "Error allocating memory\n");
return -1;
}
for (idx = 0; idx < mst->numsamples; idx++)
fdata[idx] = (float)ddata[idx];
}
else
{
fprintf (stderr, "Error, unrecognized sample type: '%c'\n", mst->sampletype);
return -1;
}
/* Create base output file name: Net.Sta.Loc.Chan.Qual.Year.Day.HourMinSec */
snprintf (baseoutfile, sizeof (baseoutfile), "%s.%s.%s.%s.%c.%04d.%03d.%02d%02d%02d",
sacnetwork, sacstation, saclocation, sacchannel,
mst->dataquality, btime.year, btime.day, btime.hour,
btime.min, btime.sec);
/* Find unused file name */
#define MAXDUPBASE 1000
for (idx = 0; idx <= MAXDUPBASE; idx++)
{
if (idx == MAXDUPBASE)
{
fprintf (stderr, "Error, over %d files with a base of %s ????, giving up...\n",
MAXDUPBASE, baseoutfile);
return -1;
}
if (idx == 0)
snprintf (outfile, sizeof (outfile), "%s.SAC%s", baseoutfile, (sacformat == 1) ? "A" : "");
else
snprintf (outfile, sizeof (outfile), "%s-%d.SAC%s", baseoutfile, idx, (sacformat == 1) ? "A" : "");
if (zipfile) /* Trap door for ZIP output, first file name always used */
break;
if (access (outfile, F_OK))
{
if (errno == ENOENT)
break;
else
{
fprintf (stderr, "Error, Cannot write output file %s: %s\n", outfile, strerror (errno));
return -1;
}
}
else if (overwrite)
{
break;
}
}
if (sacformat >= 2 && sacformat <= 4)
{
/* Byte swap the data header and data if needed */
if ((sacformat == 3 && ms_bigendianhost ()) ||
(sacformat == 4 && !ms_bigendianhost ()))
{
if (verbose)
fprintf (stderr, "Byte swapping SAC header and data\n");
swapsacheader (&sh);
for (idx = 0; idx < mst->numsamples; idx++)
{
ms_gswap4 (fdata + idx);
}
}
if (verbose > 1)
fprintf (stderr, "Writing binary SAC file: %s\n", outfile);
if (writebinarysac (&sh, fdata, mst->numsamples, outfile))
return -1;
}
else if (sacformat == 1)
{
if (verbose > 1)
fprintf (stderr, "Writing alphanumeric SAC file: %s\n", outfile);
if (writealphasac (&sh, fdata, mst->numsamples, outfile))
return -1;
}
else
{
fprintf (stderr, "Error, unrecognized format: '%d'\n", sacformat);
}
if (fdata && mst->sampletype != 'f')
free (fdata);
fprintf (stderr, "Wrote %lld samples to %s\n", (long long int)mst->numsamples, outfile);
return mst->numsamples;
} /* End of writesac() */
/***************************************************************************
* writebinarysac:
* Write binary SAC file.
*
* Returns 0 on success, and -1 on failure.
***************************************************************************/
static int
writebinarysac (struct SACHeader *sh, float *fdata, int npts, char *outfile)
{
FILE *ofp;
#ifndef NOFDZIP
ZIPentry *zentry = 0;
ssize_t writestatus = 0;
#endif /* NOFDZIP */
if (!zipfile)
{
/* Open output file */
if ((ofp = fopen (outfile, "wb")) == NULL)
{
fprintf (stderr, "Cannot open output file: %s (%s)\n",
outfile, strerror (errno));
return -1;
}
/* Write SAC header to output file */
if (fwrite (sh, sizeof (struct SACHeader), 1, ofp) != 1)
{
fprintf (stderr, "Error writing SAC header to output file\n");
return -1;
}
/* Write float data to output file */
if (fwrite (fdata, sizeof (float), npts, ofp) != npts)
{
fprintf (stderr, "Error writing SAC data to output file\n");
return -1;
}
fclose (ofp);
}
else
{
#ifndef NOFDZIP
/* Begin ZIP entry */
if (!(zentry = zs_entrybegin (zstream, outfile, time (NULL),
zipmethod, &writestatus)))
{
fprintf (stderr, "Cannot begin ZIP entry, write status: %lld\n",
(long long int)writestatus);
return -1;
}
/* Write SAC header to ZIP */
if (!zs_entrydata (zstream, zentry, (uint8_t *)sh,
sizeof (struct SACHeader), &writestatus))
{
fprintf (stderr, "Error adding entry data for %s to output ZIP, write status: %lld\n",
outfile, (long long int)writestatus);
return -1;
}
/* Write float data to ZIP */
if (!zs_entrydata (zstream, zentry, (uint8_t *)fdata,
npts * sizeof (float), &writestatus))
{
fprintf (stderr, "Error adding entry data for %s to output ZIP, write status: %lld\n",
outfile, (long long int)writestatus);
return -1;
}
/* End ZIP entry */
if (!zs_entryend (zstream, zentry, &writestatus))
{
fprintf (stderr, "Error ending ZIP entry for %s, write status: %lld\n",
outfile, (long long int)writestatus);
return 1;
}
#endif /* NOFDZIP */
}
return 0;
} /* End of writebinarysac() */
/***************************************************************************
* writealphasac:
* Write alphanumeric SAC file.
*
* Returns 0 on success, and -1 on failure.
***************************************************************************/
static int
writealphasac (struct SACHeader *sh, float *fdata, int npts, char *outfile)
{
FILE *ofp;
char buffer[2000];
char *bp;
int idx, fidx;
/* Declare and set up pointers to header variable type sections */
float *fhp = (float *)sh;
int32_t *ihp = (int32_t *)sh + (NUMFLOATHDR);
char *shp = (char *)sh + (NUMFLOATHDR * 4 + NUMINTHDR * 4);
#ifndef NOFDZIP
ZIPentry *zentry = 0;
ssize_t writestatus = 0;
#endif /* NOFDZIP */
/* Generate header in buffer */
bp = buffer;
/* Write SAC header float variables to output file, 5 variables per line */
for (idx = 0; idx < NUMFLOATHDR; idx += 5)
{
for (fidx = idx; fidx < (idx + 5) && fidx < NUMFLOATHDR; fidx++)
{
sprintf (bp, "%#15.7g", *(fhp + fidx));
bp += 15;
}
sprintf (bp, "\n");
bp += 1;
}
/* Write SAC header integer variables to output file, 5 variables per line */
for (idx = 0; idx < NUMINTHDR; idx += 5)
{
for (fidx = idx; fidx < (idx + 5) && fidx < NUMINTHDR; fidx++)
{
sprintf (bp, "%10d", *(ihp + fidx));
bp += 10;
}
sprintf (bp, "\n");
bp += 1;
}
/* Write SAC header string variables to output file, 3 variables per line */
for (idx = 0; idx < (NUMSTRHDR + 1); idx += 3)
{
if (idx == 0)
{
sprintf (bp, "%-8.8s%-16.16s", shp, shp + 8);
bp += 24;
}
else
{
for (fidx = idx; fidx < (idx + 3) && fidx < (NUMSTRHDR + 1); fidx++)
{
sprintf (bp, "%-8.8s", shp + (fidx * 8));
bp += 8;
}
}
sprintf (bp, "\n");
bp += 1;
}
if (!zipfile)
{
/* Open output file */
if ((ofp = fopen (outfile, "wb")) == NULL)
{
fprintf (stderr, "Cannot open output file: %s (%s)\n",
outfile, strerror (errno));
return -1;
}
/* Write SAC header to output file */
if (fwrite (buffer, (bp - buffer), 1, ofp) != 1)
{
fprintf (stderr, "Error writing SAC header to output file\n");
return -1;
}
/* Write float data to output file, 5 values per line */
for (idx = 0; idx < npts; idx += 5)
{
for (fidx = idx; fidx < (idx + 5) && fidx < npts && fidx >= 0; fidx++)
fprintf (ofp, "%#15.7g", *(fdata + fidx));
fprintf (ofp, "\n");
}
fclose (ofp);
}
else
{
#ifndef NOFDZIP
/* Begin ZIP entry */
if (!(zentry = zs_entrybegin (zstream, outfile, time (NULL),
zipmethod, &writestatus)))
{
fprintf (stderr, "Cannot begin ZIP entry, write status: %lld\n",
(long long int)writestatus);
return -1;
}
/* Write SAC header to ZIP */
if (!zs_entrydata (zstream, zentry, (uint8_t *)buffer,
(bp - buffer), &writestatus))
{
fprintf (stderr, "Error adding entry data for %s to output ZIP, write status: %lld\n",
outfile, (long long int)writestatus);
return -1;
}
/* Write float data to buffer and then to ZIP */
bp = buffer;
for (idx = 0; idx < npts; idx += 5)
{
for (fidx = idx; fidx < (idx + 5) && fidx < npts && fidx >= 0; fidx++)
{
sprintf (bp, "%#15.7g", *(fdata + fidx));
bp += 15;
}
sprintf (bp, "\n");
bp += 1;
/* Write float data to ZIP */
if (!zs_entrydata (zstream, zentry, (uint8_t *)buffer,
(bp - buffer), &writestatus))
{
fprintf (stderr, "Error adding entry data for %s to output ZIP, write status: %lld\n",
outfile, (long long int)writestatus);
return -1;
}
bp = buffer;
}
/* End ZIP entry */
if (!zs_entryend (zstream, zentry, &writestatus))
{
fprintf (stderr, "Error ending ZIP entry for %s, write status: %lld\n",
outfile, (long long int)writestatus);
return 1;
}
#endif /* NOFDZIP */
}
return 0;
} /* End of writealphasac() */
/***************************************************************************
* swapsacheader:
*
* Byte swap all multi-byte quantities (floats and ints) in SAC header
* struct.
*
* Returns 0 on sucess and -1 on failure.
***************************************************************************/
static int
swapsacheader (struct SACHeader *sh)
{
int32_t *ip;
int idx;
if (!sh)
return -1;
for (idx = 0; idx < (NUMFLOATHDR + NUMINTHDR); idx++)
{
ip = (int32_t *)sh + idx;
ms_gswap4 (ip);
}
return 0;
} /* End of swapsacheader() */
/***************************************************************************
* insertmetadata:
*
* Search the metadata list for the first matching source and insert
* the metadata into the SAC header if found. The source names (net,
* sta, loc, chan) are used to find a match. If metadata list entries
* include a '*' they will match everything, for example if the
* channel field is '*' all channels for the specified network,
* station and location will match the list entry.
*
* The metadata list should be populated with an array of pointers to:
* 0: Network (knetwk)
* 1: Station (kstnm)
* 2: Location (khole)
* 3: Channel (kcmpnm)
* 4: Latitude (stla)
* 5: Longitude (stlo)
* 6: Elevation (stel) [not currently used by SAC]
* 7: Depth (stdp) [not currently used by SAC]
* 8: Component Azimuth (cmpaz), degrees clockwise from north
* 9: Component Incident Angle (cmpinc), degrees from vertical
* 10: Instrument Name (kinst)
* 11: Scale Factor (scale)
* 12: Scale Frequency, unused
* 13: Scale Units, unused
* 14: Sampling rate, unused
* 15: Start time, used for matching
* 16: End time, used for matching
*
* Returns 0 on sucess, 1 when no matching metadata found and -1 on failure.
***************************************************************************/
static int
insertmetadata (struct SACHeader *sh, hptime_t sacstarttime)
{
struct listnode *mlp = metadata;
struct metanode *mn = NULL;
hptime_t sacendtime;
char *endptr;
char sacnetwork[9];
char sacstation[9];
char saclocation[9];
char sacchannel[9];
int retval = 1;
if (!mlp || !sh)
return -1;
/* Determine source name parameters for comparison */
if (strncmp (sh->knetwk, SUNDEF, 8))
ms_strncpclean (sacnetwork, sh->knetwk, 8);
else
sacnetwork[0] = '\0';
if (strncmp (sh->kstnm, SUNDEF, 8))
ms_strncpclean (sacstation, sh->kstnm, 8);
else
sacstation[0] = '\0';
if (strncmp (sh->khole, SUNDEF, 8))
ms_strncpclean (saclocation, sh->khole, 8);
else
saclocation[0] = '\0';
if (strncmp (sh->kcmpnm, SUNDEF, 8))
ms_strncpclean (sacchannel, sh->kcmpnm, 8);
else
sacchannel[0] = '\0';
/* Calculate end time of SAC data */
sacendtime = sacstarttime + (((sh->npts - 1) * sh->delta) * HPTMODULUS);
while (mlp)
{
mn = (struct metanode *)mlp->data;
/* Sanity check that source name fields are present */
if (!mn->metafields[0] || !mn->metafields[1] ||
!mn->metafields[2] || !mn->metafields[3])
{
fprintf (stderr, "insertmetadata(): error, source name fields not all present\n");
}
/* Test if network, station, location and channel; also handle simple wildcards */
else if ((!strncmp (sacnetwork, mn->metafields[0], 8) || (*(mn->metafields[0]) == '*')) &&
(!strncmp (sacstation, mn->metafields[1], 8) || (*(mn->metafields[1]) == '*')) &&
(!strncmp (saclocation, mn->metafields[2], 8) || (*(mn->metafields[2]) == '*')) &&
(!strncmp (sacchannel, mn->metafields[3], 8) || (*(mn->metafields[3]) == '*')))
{
/* Check time window match */
if (mn->starttime != HPTERROR || mn->endtime != HPTERROR)
{
/* Check for overlap with metadata window */
if (mn->starttime != HPTERROR && mn->endtime != HPTERROR)
{
if (!(sacendtime >= mn->starttime && sacstarttime <= mn->endtime))
{
mlp = mlp->next;
continue;
}
}
/* Check if data after start time */
else if (mn->starttime != HPTERROR)
{
if (sacendtime < mn->starttime)
{
mlp = mlp->next;
continue;
}
}
/* Check if data before end time */
else if (mn->endtime != HPTERROR)
{
if (sacstarttime > mn->endtime)
{
mlp = mlp->next;
continue;
}
}
}
if (verbose)
fprintf (stderr, "Inserting metadata for N: '%s', S: '%s', L: '%s', C: '%s' (%s - %s)\n",
sacnetwork, sacstation, saclocation, sacchannel,
(mn->metafields[15]) ? mn->metafields[15] : "NONE",
(mn->metafields[16]) ? mn->metafields[16] : "NONE");
/* Insert metadata into SAC header */
if (mn->metafields[4])
sh->stla = (float)strtod (mn->metafields[4], &endptr);
if (mn->metafields[5])
sh->stlo = (float)strtod (mn->metafields[5], &endptr);
if (mn->metafields[6])
sh->stel = (float)strtod (mn->metafields[6], &endptr);
if (mn->metafields[7])
sh->stdp = (float)strtod (mn->metafields[7], &endptr);
if (mn->metafields[8])
sh->cmpaz = (float)strtod (mn->metafields[8], &endptr);
if (mn->metafields[9])
{
sh->cmpinc = (float)strtod (mn->metafields[9], &endptr);
if (seedinc)
sh->cmpinc += 90;
}
if (mn->metafields[10])
ms_strncpopen (sh->kinst, mn->metafields[10], 8);
if (mn->metafields[11])
sh->scale = (float)strtod (mn->metafields[11], &endptr);
retval = 0;
break;
}
mlp = mlp->next;
}
return retval;
} /* End of insertmetadata() */
/***************************************************************************
* delaz:
*
* Calculate the angular distance (and approximately equivalent
* kilometers), azimuth and back azimuth for specified coordinates.
* Latitudes are converted to geocentric latitudes using the WGS84
* spheriod to correct for ellipticity.
*
* delta : angular distance (degrees)
* dist : distance (kilometers, 111.19 km/deg)
* azimuth : azimuth from 1 to 2 (degrees)
* backazimuth : azimuth from 2 to 1 (degrees)
*
* Returns 0 on sucess and -1 on failure.
***************************************************************************/
static int
delaz (double lat1, double lon1, double lat2, double lon2,
double *delta, double *dist, double *azimuth, double *backazimuth)
{
/* Major and minor axies for WGS84 spheriod */
const double semimajor = 6378137.0;
const double semiminor = 6356752.3142;
double ratio2, pirad, halfpi, nlat1, nlat2, gamma, a, b, sita, bsita;
ratio2 = ((semiminor * semiminor) / (semimajor * semimajor));
pirad = acos (-1.0) / 180.0;
halfpi = acos (-1.0) / 2.0;
/* Convert latitude to geocentric coordinates */
nlat1 = atan (ratio2 * tan (lat1 * pirad));
nlat2 = atan (ratio2 * tan (lat2 * pirad));
/* Great circle calculation for delta and azimuth */
gamma = (lon2 - lon1) * pirad;
a = (halfpi - nlat2);
b = (halfpi - nlat1);
if (a == 0.0)
sita = 1.0;
else if (nlat2 == 0.0)
sita = 0.0;
else
sita = sin (b) / tan (a);
if (b == 0.0)
bsita = 1.0;
else if (nlat1 == 0.0)
bsita = 0.0;
else
bsita = sin (a) / tan (b);
*delta = acos (cos (a) * cos (b) + sin (a) * sin (b) * cos (gamma)) / pirad;
if (FLTEQUAL (*delta, 0.0))
*delta = 0.0;
/* 111.19 km/deg */
*dist = *delta * 111.19;
if (FLTEQUAL (*dist, 0.0))
*dist = 0.0;
*azimuth = atan2 (sin (gamma), sita - cos (gamma) * cos (b)) / pirad;
if (FLTEQUAL (*azimuth, 0.0))
*azimuth = 0.0;
else if (*azimuth < 0.0)
*azimuth += 360;
*backazimuth = atan2 (-sin (gamma), bsita - cos (gamma) * cos (a)) / pirad;
if (FLTEQUAL (*backazimuth, 0.0))
*backazimuth = 0.0;
else if (*backazimuth < 0.0)
*backazimuth += 360;
return 0;
} /* End of delaz() */
/***************************************************************************
* parameter_proc:
* Process the command line parameters.
*
* Returns 0 on success, and -1 on failure.
***************************************************************************/
static int
parameter_proc (int argcount, char **argvec)
{
char *coorstr = 0;
char *metafile = 0;
char *metaline = 0;
char *eventstr = 0;
char *selectfile = 0;
int optind;
/* Process all command line arguments */
for (optind = 1; optind < argcount; optind++)
{
if (strcmp (argvec[optind], "-V") == 0)
{
fprintf (stderr, "%s version: %s\n", PACKAGE, VERSION);
exit (0);
}
else if (strcmp (argvec[optind], "-h") == 0)
{
usage (0);
exit (0);
}
else if (strcmp (argvec[optind], "-H") == 0)
{
usage (1);
exit (0);
}
else if (strncmp (argvec[optind], "-v", 2) == 0)
{
verbose += strspn (&argvec[optind][1], "v");
}
else if (strcmp (argvec[optind], "-O") == 0)
{
overwrite = 1;
}
else if (strcmp (argvec[optind], "-k") == 0)
{
coorstr = getoptval (argcount, argvec, optind++, 1);
}
else if (strcmp (argvec[optind], "-m") == 0)
{
metafile = getoptval (argcount, argvec, optind++, 0);
}
else if (strcmp (argvec[optind], "-M") == 0)
{
metaline = getoptval (argcount, argvec, optind++, 0);
if ( addmetadata(metaline) < 0 )
{
fprintf (stderr, "Error adding metadata fields for line:\n%s\n", metaline);
}
}
else if (strcmp (argvec[optind], "-msi") == 0)
{
seedinc = 1;
}
else if (strcmp (argvec[optind], "-E") == 0)
{
eventstr = getoptval (argcount, argvec, optind++, 0);
}
else if (strcmp (argvec[optind], "-l") == 0)
{
selectfile = getoptval (argcount, argvec, optind++, 0);
}
else if (strcmp (argvec[optind], "-f") == 0)
{
sacformat = strtoul (getoptval (argcount, argvec, optind++, 0), NULL, 10);
}
else if (strcmp (argvec[optind], "-N") == 0)
{
network = getoptval (argcount, argvec, optind++, 0);
}
else if (strcmp (argvec[optind], "-S") == 0)
{
station = getoptval (argcount, argvec, optind++, 0);
}
else if (strcmp (argvec[optind], "-L") == 0)
{
location = getoptval (argcount, argvec, optind++, 0);
}
else if (strcmp (argvec[optind], "-C") == 0)
{
channel = getoptval (argcount, argvec, optind++, 0);
}
else if (strcmp (argvec[optind], "-r") == 0)
{
reclen = strtoul (getoptval (argcount, argvec, optind++, 0), NULL, 10);
}
else if (strcmp (argvec[optind], "-dr") == 0)
{
deriverate = 1;
}
else if (strcmp (argvec[optind], "-i") == 0)
{
indifile = 1;
}
else if (strcmp (argvec[optind], "-ic") == 0)
{
indichannel = 1;
}
#ifndef NOFDZIP
else if (strcmp (argvec[optind], "-z") == 0)
{
zipfile = getoptval (argcount, argvec, optind++, 1);
zipmethod = ZS_DEFLATE;
}
else if (strcmp (argvec[optind], "-z0") == 0)
{
zipfile = getoptval (argcount, argvec, optind++, 1);
zipmethod = ZS_STORE;
}
#endif
else if (strncmp (argvec[optind], "-", 1) == 0 &&
strlen (argvec[optind]) > 1)
{
fprintf (stderr, "Unknown option: %s\n", argvec[optind]);
exit (1);
}
else
{
/* Add the file name to the intput file list */
if (!addnode (&filelist, NULL, 0, argvec[optind], strlen (argvec[optind]) + 1))
{
fprintf (stderr, "Error adding file name to list\n");
}
}
}
/* Make sure an input files were specified */
if (filelist == 0)
{
fprintf (stderr, "No input files were specified\n\n");
fprintf (stderr, "%s version %s\n\n", PACKAGE, VERSION);
fprintf (stderr, "Try %s -h for usage\n", PACKAGE);
exit (1);
}
/* Report the program version */
if (verbose)
fprintf (stderr, "%s version: %s\n", PACKAGE, VERSION);
/* Check the input files for any list files, if any are found
* remove them from the list and add the contained list */
if (filelist)
{
struct listnode *prevln, *ln;
char *lfname;
prevln = ln = filelist;
while (ln != 0)
{
lfname = ln->data;
if (*lfname == '@')
{
/* Remove this node from the list */
if (ln == filelist)
filelist = ln->next;
else
prevln->next = ln->next;
/* Skip the '@' first character */
if (*lfname == '@')
lfname++;
/* Read list file */
readlistfile (lfname);
/* Free memory for this node */
if (ln->key)
free (ln->key);
free (ln->data);
free (ln);
}
else
{
prevln = ln;
}
ln = ln->next;
}
}
/* Parse coordinates */
if (coorstr)
{
char *lat, *lon;
char *endptr = 0;
lat = coorstr;
lon = 0;
if ((lon = strchr (lat, '/')))
{
*lon++ = '\0';
}
else
{
fprintf (stderr, "Error parsing coordinates (LAT/LON): '%s'\n", coorstr);
fprintf (stderr, "Try %s -h for usage\n", PACKAGE);
return -1;
}
if (lat)
if (*lat)
if ((latitude = strtod (lat, &endptr)) == 0.0 && endptr == lat)
{
fprintf (stderr, "Error parsing station latitude: '%s'\n", lat);
return -1;
}
if (lon)
if (*lon)
if ((longitude = strtod (lon, &endptr)) == 0.0 && endptr == lon)
{
fprintf (stderr, "Error parsing station longitude: '%s'\n", lon);
return -1;
}
}
/* Parse event information */
if (eventstr)
{
char *etime, *elat, *elon, *edepth, *ename;
char *endptr = 0;
etime = eventstr;
elat = elon = edepth = ename = 0;
if ((elat = strchr (etime, '/')))
{
*elat++ = '\0';
if ((elon = strchr (elat, '/')))
{
*elon++ = '\0';
if ((edepth = strchr (elon, '/')))
{
*edepth++ = '\0';
if ((ename = strchr (edepth, '/')))
{
*ename++ = '\0';
}
}
}
}
/* Parse event time */
eventtime = ms_seedtimestr2hptime (etime);
if (eventtime == HPTERROR)
{
fprintf (stderr, "Error parsing event time: '%s'\n", etime);
fprintf (stderr, "Try %s -h for usage\n", PACKAGE);
return -1;
}
/* Process remaining event information */
if (elat)
if (*elat)
if ((eventlat = strtod (elat, &endptr)) == 0.0 && endptr == elat)
{
fprintf (stderr, "Error parsing event latitude: '%s'\n", elat);
return -1;
}
if (elon)
if (*elon)
if ((eventlon = strtod (elon, &endptr)) == 0.0 && endptr == elon)
{
fprintf (stderr, "Error parsing event longitude: '%s'\n", elon);
return -1;
}
if (edepth)
if (*edepth)
if ((eventdepth = strtod (edepth, &endptr)) == 0.0 && endptr == edepth)
{
fprintf (stderr, "Error parsing event depth: '%s'\n", edepth);
return -1;
}
if (ename)
if (*ename)
eventname = ename;
}
/* Read data selection file */
if (selectfile)
{
if (ms_readselectionsfile (&selections, selectfile) < 0)
{
fprintf (stderr, "Cannot read data selection file\n");
return -1;
}
if (verbose > 1)
ms_printselections (selections);
}
/* Read metadata file if specified */
if (metafile)
{
if (readmetadata (metafile))
{
fprintf (stderr, "Error reading metadata file\n");
return -1;
}
}
return 0;
} /* End of parameter_proc() */
/***************************************************************************
* getoptval:
* Return the value to a command line option; checking that the value is
* itself not an option (starting with '-') and is not past the end of
* the argument list.
*
* argcount: total arguments in argvec
* argvec: argument list
* argopt: index of option to process, value is expected to be at argopt+1
* dasharg: can be a dash boolean?
*
* Returns value on success and exits with error message on failure
***************************************************************************/
static char *
getoptval (int argcount, char **argvec, int argopt, int dasharg)
{
if (argvec == NULL || argvec[argopt] == NULL)
{
fprintf (stderr, "getoptval(): NULL option requested\n");
exit (1);
return 0;
}
/* When the value potentially starts with a dash (-) */
if ((argopt + 1) < argcount && dasharg)
return argvec[argopt + 1];
/* Otherwise check that the value is not another option */
if ((argopt + 1) < argcount && *argvec[argopt + 1] != '-')
return argvec[argopt + 1];
fprintf (stderr, "Option %s requires a value\n", argvec[argopt]);
exit (1);
return 0;
} /* End of getoptval() */
/***************************************************************************
* readlistfile:
*
* Read a list of files from a file and add them to the filelist for
* input data. The filename is expected to be the last
* space-separated field on the line.
*
* Returns the number of file names parsed from the list or -1 on error.
***************************************************************************/
static int
readlistfile (char *listfile)
{
FILE *fp;
char line[1024];
char *ptr;
int filecnt = 0;
char filename[1024];
char *lastfield = 0;
int fields = 0;
int wspace;
/* Open the list file */
if ((fp = fopen (listfile, "rb")) == NULL)
{
if (errno == ENOENT)
{
fprintf (stderr, "Could not find list file %s\n", listfile);
return -1;
}
else
{
fprintf (stderr, "Error opening list file %s: %s\n",
listfile, strerror (errno));
return -1;
}
}
if (verbose)
fprintf (stderr, "Reading list of input files from %s\n", listfile);
while ((fgets (line, sizeof (line), fp)) != NULL)
{
/* Truncate line at first \r or \n, count space-separated fields
* and track last field */
fields = 0;
wspace = 0;
ptr = line;
while (*ptr)
{
if (*ptr == '\r' || *ptr == '\n' || *ptr == '\0')
{
*ptr = '\0';
break;
}
else if (*ptr != ' ')
{
if (wspace || ptr == line)
{
fields++;
lastfield = ptr;
}
wspace = 0;
}
else
{
wspace = 1;
}
ptr++;
}
/* Skip empty lines */
if (!lastfield)
continue;
if (fields >= 1 && fields <= 3)
{
fields = sscanf (lastfield, "%s", filename);
if (fields != 1)
{
fprintf (stderr, "Error parsing file name from: %s\n", line);
continue;
}
if (verbose > 1)
fprintf (stderr, "Adding '%s' to input file list\n", filename);
/* Add file name to the intput file list */
if (!addnode (&filelist, NULL, 0, filename, strlen (filename) + 1))
{
fprintf (stderr, "Error adding file name to list\n");
}
filecnt++;
continue;
}
}
fclose (fp);
return filecnt;
} /* End readlistfile() */
/***************************************************************************
* addmetadata:
*
* Parse and add a metadata entry into a structured list. The
* metadata line should contain the following fields (comma or bar
* separated) in this order:
*
* The metadata list should be populated with an array of pointers to:
* 0: Network (knetwk)
* 1: Station (kstnm)
* 2: Location (khole)
* 3: Channel (kcmpnm)
* 4: Latitude (stla)
* 5: Longitude (stlo)
* 6: Elevation (stel) [not currently used by SAC]
* 7: Depth (stdp) [not currently used by SAC]
* 8: Component Azimuth (cmpaz), degrees clockwise from north
* 9: Component Incident Angle (cmpinc), degrees from vertical
* 10: Instrument Name (kinst)
* 11: Scale Factor (scale)
* 12: Scale Frequency, unused
* 13: Scale Units, unused
* 14: Sampling rate, unused
* 15: Start time, used for matching
* 16: End time, used for matching
*
* Any lines not containing at least 3 separators (commas or vertical
* bars) are not considered complete. If the first 4 fields are
* empty, they will be stored as empty strings, whereas any other
* empty fields will be set to NULL.
*
* If the separators are commas the component inclination is assumed
* to be in the SAC convention. If the separators are vertical bars
* (|) the component inclination is assumed to be a SEED dip and the
* seedinc variable will be set to 1.
*
* Returns number of fields parsed on success and -1 on failure.
***************************************************************************/
static int
addmetadata (char *metaline)
{
struct metanode mn;
char *lineptr;
char *fp;
char delim;
int fields = 0;
int commas = 0;
int bars = 0;
int idx;
if (!metaline)
return -1;
/* Count the number of commas */
fp = metaline;
while ((fp = strchr (fp, ',')))
{
commas++;
fp++;
}
/* Count the number of vertical bars */
fp = metaline;
while ((fp = strchr (fp, '|')))
{
bars++;
fp++;
}
/* Set delimiter, if vertial bars expect "inclination" to be SEED dip convention */
if (bars > 0)
{
delim = '|';
seedinc = 1;
}
else
{
delim = ',';
}
/* Must have at least 3 separators for Net, Sta, Loc, Chan ... */
if (((delim == '|') ? bars : commas) < 3)
{
if (verbose > 1)
fprintf (stderr, "Skipping metadata line: %s\n", metaline);
return 0;
}
/* Create a copy of the line */
lineptr = strdup (metaline);
mn.metafields[0] = fp = lineptr;
mn.starttime = HPTERROR;
mn.endtime = HPTERROR;
/* Separate line on delimiter and index in metafields array */
for (idx = 1; idx < MAXMETAFIELDS; idx++)
{
mn.metafields[idx] = NULL;
if (fp)
{
if ((fp = strchr (fp, delim)))
{
*fp++ = '\0';
if (idx <= 3)
mn.metafields[idx] = fp;
else if (*fp != delim && *fp != '\0')
mn.metafields[idx] = fp;
fields++;
}
}
}
/* Trim last field if more fields exist */
if (fp && (fp = strchr (fp, ',')))
*fp = '\0';
/* Convert dash-dash location codes to empty strings */
if (!strcmp (mn.metafields[2], "--"))
{
mn.metafields[2] = "";
}
/* Parse and convert start time */
if (mn.metafields[15])
{
if ((mn.starttime = ms_timestr2hptime (mn.metafields[15])) == HPTERROR)
{
fprintf (stderr, "Error parsing metadata start time: '%s'\n", mn.metafields[15]);
exit (1);
}
}
/* Parse and convert end time */
if (mn.metafields[16])
{
if ((mn.endtime = ms_timestr2hptime (mn.metafields[16])) == HPTERROR)
{
fprintf (stderr, "Error parsing metadata end time: '%s'\n", mn.metafields[16]);
exit (1);
}
}
/* Add the metanode to the metadata list */
if (!addnode (&metadata, NULL, 0, &mn, sizeof (struct metanode)))
{
fprintf (stderr, "Error adding metadata fields to list\n");
}
return fields;
} /* End of addmetadata() */
/***************************************************************************
* readmetadata:
*
* Read a file of metadata lines and add to a structured list. Each
* line is processed by addmetadata() and should be in the format
* expected by that routine.
*
* Any lines beginning with '#' are skipped, think comments.
*
* Returns 0 on sucess and -1 on failure.
***************************************************************************/
static int
readmetadata (char *metafile)
{
FILE *mfp;
char line[1024];
char *fp;
int linecount = 0;
if (!metafile)
return -1;
if ((mfp = fopen (metafile, "rb")) == NULL)
{
fprintf (stderr, "Cannot open metadata output file: %s (%s)\n",
metafile, strerror (errno));
return -1;
}
if (verbose)
fprintf (stderr, "Reading station/channel metadata from %s\n", metafile);
while (fgets (line, sizeof (line), mfp))
{
linecount++;
/* Truncate at line return if any */
if ((fp = strchr (line, '\n')))
*fp = '\0';
/* Check for comment line beginning with '#' */
if (line[0] == '#')
{
if (verbose > 1)
fprintf (stderr, "Skipping comment line: %s\n", line);
continue;
}
if ( addmetadata(line) < 0 )
{
fprintf (stderr, "Error adding metadata fields to list for line %d:\n%s\n", linecount, line);
}
}
fclose (mfp);
return 0;
} /* End of readmetadata() */
/***************************************************************************
* addnode:
*
* Add node to the specified list. Copies of the key and data are created.
*
* Return a pointer to the added node on success and NULL on error.
***************************************************************************/
static struct listnode *
addnode (struct listnode **listroot, void *key, int keylen,
void *data, int datalen)
{
struct listnode *lastlp, *newlp;
if (data == NULL)
{
fprintf (stderr, "addnode(): No data specified\n");
return NULL;
}
lastlp = *listroot;
while (lastlp != 0)
{
if (lastlp->next == 0)
break;
lastlp = lastlp->next;
}
/* Create new listnode */
newlp = (struct listnode *)malloc (sizeof (struct listnode));
memset (newlp, 0, sizeof (struct listnode));
if (key)
{
newlp->key = malloc (keylen);
memcpy (newlp->key, key, keylen);
}
if (data)
{
newlp->data = malloc (datalen);
memcpy (newlp->data, data, datalen);
}
newlp->next = 0;
if (lastlp == 0)
*listroot = newlp;
else
lastlp->next = newlp;
return newlp;
} /* End of addnode() */
/***************************************************************************
* usage:
* Print the usage message and exit.
***************************************************************************/
static void
usage (int level)
{
fprintf (stderr, "%s version: %s\n\n", PACKAGE, VERSION);
fprintf (stderr, "Convert miniSEED data to SAC\n\n");
fprintf (stderr, "Usage: %s [options] input1.mseed [input2.mseed ...]\n\n", PACKAGE);
fprintf (stderr,
" ## Options ##\n"
" -V Report program version\n"
" -h Show this usage message\n"
" -H Print an extended usage message\n"
" -v Be more verbose, multiple flags can be used\n"
" -O Overwrite existing output files, default creates new file names\n"
"\n"
" -k lat/lon Specify station coordinates as 'Latitude/Longitude' in degrees\n"
" -m metafile File containing channel metadata (coordinates and more)\n"
" -M metaline Channel metadata, same format as lines in metafile\n"
" -msi Convert component inclination/dip from SEED to SAC convention\n"
" -E event Specify event parameters as 'Time[/Lat][/Lon][/Depth][/Name]'\n"
" e.g. '2006,123,15:27:08.7/-20.33/-174.03/65.5/Tonga'\n"
" -l selectfile Read a list of selections from file, used for subsetting\n"
"\n"
" -f format Specify SAC file format (default is 2:binary):\n"
" 1=alpha, 2=binary (host byte order),\n"
" 3=binary (little-endian), 4=binary (big-endian)\n"
"\n"
" More options are available, to see their description use the -H option\n"
"\n");
if (level >= 1)
{
fprintf (stderr,
" -N network Specify the network code, overrides any value in the SEED\n"
" -S station Specify the station code, overrides any value in the SEED\n"
" -L location Specify the location code, overrides any value in the SEED\n"
" -C channel Specify the channel code, overrides any value in the SEED\n"
" -r bytes Specify SEED record length in bytes, autodetected by default\n"
" -i Process each input file individually instead of merged\n"
" -ic Process each channel individually, data should be well ordered\n"
" -dr Use the sampling rate derived from the time stamps instead\n"
" of the sample rate denoted in the input data\n");
#ifndef NOFDZIP
fprintf (stderr,
" -z zipfile Write all SAC files to a ZIP archive, use '-' for stdout\n"
" -z0 zipfile Same as -z but do not compress archive entries\n");
#endif
fprintf (stderr, "\n");
}
} /* End of usage() */
mseed2sac-2.2+ds1/src/sacformat.h 0000664 0000000 0000000 00000036512 13225706503 0016637 0 ustar 00root root 0000000 0000000 #ifndef SAC_FORMAT_H
#define SAC_FORMAT_H
/* Version: 2006.137 */
#ifdef __cplusplus
extern "C" {
#endif
#define REGCONV 100
#define SACHEADERLEN 632 /* SAC header length in bytes (only version 6?) */
#define NUMFLOATHDR 70 /* Number of float header variables, 4 bytes each */
#define NUMINTHDR 40 /* Number of integer header variables, 4 bytes each */
#define NUMSTRHDR 23 /* Number of string header variables, 22x8 bytes + 1x16 bytes */
/* Undefined values for float, integer and string header variables */
#define FUNDEF -12345.0
#define IUNDEF -12345
#define SUNDEF "-12345 "
/* SAC header structure as it exists in binary SAC files */
struct SACHeader
{
float delta; /* RF time increment, sec */
float depmin; /* minimum amplitude */
float depmax; /* maximum amplitude */
float scale; /* amplitude scale factor */
float odelta; /* observed time inc */
float b; /* RD initial value, time */
float e; /* RD final value, time */
float o; /* event start, sec < nz. */
float a; /* 1st arrival time */
float fmt; /* internal use */
float t0; /* user-defined time pick */
float t1; /* user-defined time pick */
float t2; /* user-defined time pick */
float t3; /* user-defined time pick */
float t4; /* user-defined time pick */
float t5; /* user-defined time pick */
float t6; /* user-defined time pick */
float t7; /* user-defined time pick */
float t8; /* user-defined time pick */
float t9; /* user-defined time pick */
float f; /* event end, sec > nz */
float resp0; /* instrument respnse parm*/
float resp1; /* instrument respnse parm*/
float resp2; /* instrument respnse parm*/
float resp3; /* instrument respnse parm*/
float resp4; /* instrument respnse parm*/
float resp5; /* instrument respnse parm*/
float resp6; /* instrument respnse parm*/
float resp7; /* instrument respnse parm*/
float resp8; /* instrument respnse parm*/
float resp9; /* instrument respnse parm*/
float stla; /* T station latititude */
float stlo; /* T station longitude */
float stel; /* T station elevation, m */
float stdp; /* T station depth, m */
float evla; /* event latitude */
float evlo; /* event longitude */
float evel; /* event elevation */
float evdp; /* event depth */
float mag; /* reserved for future use*/
float user0; /* available to user */
float user1; /* available to user */
float user2; /* available to user */
float user3; /* available to user */
float user4; /* available to user */
float user5; /* available to user */
float user6; /* available to user */
float user7; /* available to user */
float user8; /* available to user */
float user9; /* available to user */
float dist; /* stn-event distance, km */
float az; /* event-stn azimuth */
float baz; /* stn-event azimuth */
float gcarc; /* stn-event dist, degrees*/
float sb; /* internal use */
float sdelta; /* internal use */
float depmen; /* mean value, amplitude */
float cmpaz; /* T component azimuth */
float cmpinc; /* T component inclination */
float xminimum; /* reserved for future use*/
float xmaximum; /* reserved for future use*/
float yminimum; /* reserved for future use*/
float ymaximum; /* reserved for future use*/
float unused6; /* reserved for future use*/
float unused7; /* reserved for future use*/
float unused8; /* reserved for future use*/
float unused9; /* reserved for future use*/
float unused10; /* reserved for future use*/
float unused11; /* reserved for future use*/
float unused12; /* reserved for future use*/
int32_t nzyear; /* F zero time of file, yr */
int32_t nzjday; /* F zero time of file, day */
int32_t nzhour; /* F zero time of file, hr */
int32_t nzmin; /* F zero time of file, min */
int32_t nzsec; /* F zero time of file, sec */
int32_t nzmsec; /* F zero time of file, millisec*/
int32_t nvhdr; /* internal use (version) */
int32_t norid; /* origin ID */
int32_t nevid; /* event ID */
int32_t npts; /* RF number of samples */
int32_t nsnpts; /* internal use */
int32_t nwfid; /* waveform ID */
int32_t nxsize; /* reserved for future use*/
int32_t nysize; /* reserved for future use*/
int32_t unused15; /* reserved for future use*/
int32_t iftype; /* RA type of file */
int32_t idep; /* type of amplitude */
int32_t iztype; /* zero time equivalence */
int32_t unused16; /* reserved for future use*/
int32_t iinst; /* recording instrument */
int32_t istreg; /* stn geographic region */
int32_t ievreg; /* event geographic region*/
int32_t ievtyp; /* event type */
int32_t iqual; /* quality of data */
int32_t isynth; /* synthetic data flag */
int32_t imagtyp; /* reserved for future use*/
int32_t imagsrc; /* reserved for future use*/
int32_t unused19; /* reserved for future use*/
int32_t unused20; /* reserved for future use*/
int32_t unused21; /* reserved for future use*/
int32_t unused22; /* reserved for future use*/
int32_t unused23; /* reserved for future use*/
int32_t unused24; /* reserved for future use*/
int32_t unused25; /* reserved for future use*/
int32_t unused26; /* reserved for future use*/
int32_t leven; /* RA data-evenly-spaced flag*/
int32_t lpspol; /* station polarity flag */
int32_t lovrok; /* overwrite permission */
int32_t lcalda; /* calc distance, azimuth */
int32_t unused27; /* reserved for future use*/
char kstnm[8]; /* F station name */
char kevnm[16]; /* event name */
char khole[8]; /* man-made event name */
char ko[8]; /* event origin time id */
char ka[8]; /* 1st arrival time ident */
char kt0[8]; /* time pick 0 ident */
char kt1[8]; /* time pick 1 ident */
char kt2[8]; /* time pick 2 ident */
char kt3[8]; /* time pick 3 ident */
char kt4[8]; /* time pick 4 ident */
char kt5[8]; /* time pick 5 ident */
char kt6[8]; /* time pick 6 ident */
char kt7[8]; /* time pick 7 ident */
char kt8[8]; /* time pick 8 ident */
char kt9[8]; /* time pick 9 ident */
char kf[8]; /* end of event ident */
char kuser0[8]; /* available to user */
char kuser1[8]; /* available to user */
char kuser2[8]; /* available to user */
char kcmpnm[8]; /* F component name */
char knetwk[8]; /* network name */
char kdatrd[8]; /* date data read */
char kinst[8]; /* instrument name */
};
/* A SAC header null value initializer
* Usage: struct SACHeader sh = NullSACHeader; */
#define NullSACHeader { \
-12345.0, -12345.0, -12345.0, -12345.0, -12345.0, \
-12345.0, -12345.0, -12345.0, -12345.0, -12345.0, \
-12345.0, -12345.0, -12345.0, -12345.0, -12345.0, \
-12345.0, -12345.0, -12345.0, -12345.0, -12345.0, \
-12345.0, -12345.0, -12345.0, -12345.0, -12345.0, \
-12345.0, -12345.0, -12345.0, -12345.0, -12345.0, \
-12345.0, -12345.0, -12345.0, -12345.0, -12345.0, \
-12345.0, -12345.0, -12345.0, -12345.0, -12345.0, \
-12345.0, -12345.0, -12345.0, -12345.0, -12345.0, \
-12345.0, -12345.0, -12345.0, -12345.0, -12345.0, \
-12345.0, -12345.0, -12345.0, -12345.0, -12345.0, \
-12345.0, -12345.0, -12345.0, -12345.0, -12345.0, \
-12345.0, -12345.0, -12345.0, -12345.0, -12345.0, \
-12345.0, -12345.0, -12345.0, -12345.0, -12345.0, \
-12345, -12345, -12345, -12345, -12345, \
-12345, -12345, -12345, -12345, -12345, \
-12345, -12345, -12345, -12345, -12345, \
-12345, -12345, -12345, -12345, -12345, \
-12345, -12345, -12345, -12345, -12345, \
-12345, -12345, -12345, -12345, -12345, \
-12345, -12345, -12345, -12345, -12345, \
-12345, -12345, -12345, -12345, -12345, \
{ '-','1','2','3','4','5',' ',' ' }, \
{ '-','1','2','3','4','5',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ' }, \
{ '-','1','2','3','4','5',' ',' ' },{ '-','1','2','3','4','5',' ',' ' }, \
{ '-','1','2','3','4','5',' ',' ' },{ '-','1','2','3','4','5',' ',' ' }, \
{ '-','1','2','3','4','5',' ',' ' },{ '-','1','2','3','4','5',' ',' ' }, \
{ '-','1','2','3','4','5',' ',' ' },{ '-','1','2','3','4','5',' ',' ' }, \
{ '-','1','2','3','4','5',' ',' ' },{ '-','1','2','3','4','5',' ',' ' }, \
{ '-','1','2','3','4','5',' ',' ' },{ '-','1','2','3','4','5',' ',' ' }, \
{ '-','1','2','3','4','5',' ',' ' },{ '-','1','2','3','4','5',' ',' ' }, \
{ '-','1','2','3','4','5',' ',' ' },{ '-','1','2','3','4','5',' ',' ' }, \
{ '-','1','2','3','4','5',' ',' ' },{ '-','1','2','3','4','5',' ',' ' }, \
{ '-','1','2','3','4','5',' ',' ' },{ '-','1','2','3','4','5',' ',' ' }, \
{ '-','1','2','3','4','5',' ',' ' } \
};
/* definitions of constants for SAC enumerated data values */
#define IREAL 0 /* undocumented */
#define ITIME 1 /* file: time series data */
#define IRLIM 2 /* file: real&imag spectrum */
#define IAMPH 3 /* file: ampl&phas spectrum */
#define IXY 4 /* file: gen'l x vs y data */
#define IUNKN 5 /* x data: unknown type */
/* zero time: unknown */
/* event type: unknown */
#define IDISP 6 /* x data: displacement (nm) */
#define IVEL 7 /* x data: velocity (nm/sec) */
#define IACC 8 /* x data: accel (cm/sec/sec)*/
#define IB 9 /* zero time: start of file */
#define IDAY 10 /* zero time: 0000 of GMT day*/
#define IO 11 /* zero time: event origin */
#define IA 12 /* zero time: 1st arrival */
#define IT0 13 /* zero time: user timepick 0*/
#define IT1 14 /* zero time: user timepick 1*/
#define IT2 15 /* zero time: user timepick 2*/
#define IT3 16 /* zero time: user timepick 3*/
#define IT4 17 /* zero time: user timepick 4*/
#define IT5 18 /* zero time: user timepick 5*/
#define IT6 19 /* zero time: user timepick 6*/
#define IT7 20 /* zero time: user timepick 7*/
#define IT8 21 /* zero time: user timepick 8*/
#define IT9 22 /* zero time: user timepick 9*/
#define IRADNV 23 /* undocumented */
#define ITANNV 24 /* undocumented */
#define IRADEV 25 /* undocumented */
#define ITANEV 26 /* undocumented */
#define INORTH 27 /* undocumented */
#define IEAST 28 /* undocumented */
#define IHORZA 29 /* undocumented */
#define IDOWN 30 /* undocumented */
#define IUP 31 /* undocumented */
#define ILLLBB 32 /* undocumented */
#define IWWSN1 33 /* undocumented */
#define IWWSN2 34 /* undocumented */
#define IHGLP 35 /* undocumented */
#define ISRO 36 /* undocumented */
/* Source types */
#define INUCL 37 /* event type: nuclear shot */
#define IPREN 38 /* event type: nuke pre-shot */
#define IPOSTN 39 /* event type: nuke post-shot*/
#define IQUAKE 40 /* event type: earthquake */
#define IPREQ 41 /* event type: foreshock */
#define IPOSTQ 42 /* event type: aftershock */
#define ICHEM 43 /* event type: chemical expl */
#define IOTHER 44 /* event type: other source */
#define IQB 72 /* Quarry Blast or mine expl. confirmed by quarry */
#define IQB1 73 /* Quarry or mine blast with designed shot information-ripple fired */
#define IQB2 74 /* Quarry or mine blast with observed shot information-ripple fired */
#define IQBX 75 /* Quarry or mine blast - single shot */
#define IQMT 76 /* Quarry or mining-induced events: tremors and rockbursts */
#define IEQ 77 /* Earthquake */
#define IEQ1 78 /* Earthquakes in a swarm or aftershock sequence */
#define IEQ2 79 /* Felt earthquake */
#define IME 80 /* Marine explosion */
#define IEX 81 /* Other explosion */
#define INU 82 /* Nuclear explosion */
#define INC 83 /* Nuclear cavity collapse */
#define IO_ 84 /* Other source of known origin */
#define IL 85 /* Local event of unknown origin */
#define IR 86 /* Regional event of unknown origin */
#define IT 87 /* Teleseismic event of unknown origin */
#define IU 88 /* Undetermined or conflicting information */
#define IEQ3 89 /* Damaging earthquake */
#define IEQ0 90 /* Probable earthquake */
#define IEX0 91 /* Probable explosion */
#define IQC 92 /* Mine collapse */
#define IQB0 93 /* Probable Mine Blast */
#define IGEY 94 /* Geyser */
#define ILIT 95 /* Light */
#define IMET 96 /* Meteoric Event */
#define IODOR 97 /* Odors */
#define IOS 103 /* Other source: Known origin*/
/* data quality: other problm*/
#define IGOOD 45 /* data quality: good */
#define IGLCH 46 /* data quality: has glitches*/
#define IDROP 47 /* data quality: has dropouts*/
#define ILOWSN 48 /* data quality: low s/n */
#define IRLDTA 49 /* data is real data */
#define IVOLTS 50 /* file: velocity (volts) */
/* Magnitude type and source */
#define IMB 52 /* Bodywave Magnitude */
#define IMS 53 /* Surface Magnitude */
#define IML 54 /* Local Magnitude */
#define IMW 55 /* Moment Magnitude */
#define IMD 56 /* Duration Magnitude */
#define IMX 57 /* User Defined Magnitude */
#define INEIC 58 /* INEIC */
#define IPDEQ 59 /* IPDE */
#define IPDEW 60 /* IPDE */
#define IPDE 61 /* IPDE */
#define IISC 62 /* IISC */
#define IREB 63 /* IREB */
#define IUSGS 64 /* IUSGS */
#define IBRK 65 /* IBRK */
#define ICALTECH 66 /* ICALTECH */
#define ILLNL 67 /* ILLNL */
#define IEVLOC 68 /* IEVLOC */
#define IJSOP 69 /* IJSOP */
#define IUSER 70 /* IUSER */
#define IUNKNOWN 71 /* IUNKNOWN */
#ifdef __cplusplus
}
#endif
#endif /* SAC_FORMAT_H */