package edu.sc.seis.seisFile.segd; import java.io.DataInput; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Arrays; import java.util.Date; import com.isti.traceview.common.TimeInterval; import org.apache.log4j.Logger; public class SegdRecord { private static final Logger logger = Logger.getLogger(SegdRecord.class); public enum Format { BINARY_MULTIPLEXED_20_BIT, // (not implemented) BINARY_DEMUX_20_BIT, // (not implemented) QUATERNARY_MULTIPLEXED_8_BIT, // (not implemented QUATERNARY_MULTIPLEXED_16_BIT, // (not implemented) HEXADECIMAL_MULTIPLEXED_8_BIT, // (not implemented) HEXADECIMAL_MULTIPLEXED_16_BIT, // (not implemented) HEXADECIMAL_MULTIPLEXED_32_BIT, // (not implemented) COMPLIMENT_2_INTEGER_MULTIPLEXED_24_BIT, // (not implemented) COMPLIMENT_2_INTEGER_MULTIPLEXED_32_BIT, // (not implemented) COMPLIMENT_2_INTEGER_DEMUX_24_BIT, // (not implemented) COMPLIMENT_2_INTEGER_DEMUX_32_BIT, // (not implemented) QUATERNARY_DEMUX_8_BIT, // (not implemented) QUATERNARY_DEMUX_16_BIT, // (not implemented) HEXADECIMAL_DEMUX_8_BIT, // (not implemented) HEXADECIMAL_DEMUX_16_BIT, // (not implemented) HEXADECIMAL_DEMUX_32_BIT, // (not implemented) IEEE_MULTIPLEXED_32_BIT, IEEE_DEMUX_32_BIT }; public enum Polarity { UNTESTED, ZERO, DEGREES_45, DEGREES_90, DEGREES_135, DEGREES_180, DEGREES_225, DEGREES_270, DEGREES_315, UNASSIGNED }; public enum RecordType { TEST_RECORD, PARALLEL_CHANNEL_TEST, DIRECT_CHANNEL_TEST, NORMAL_RECORD, OTHER }; // -----------General header 1 data------------ private int fileNumber = -1; private Format format; private short[] general_constants = new short[12]; private short additionalGeneralHeaderBlocksNumber; private Date date = null; private int manufacturer_code = -1; private int manufacturer_serial_num = -1; private double base_scan_interval = -1.0; private Polarity polarity; private RecordType recordType; private double recordLength = -1.0; private int scanTypes_per_record = -1; private int channelSets_per_scanType = -1; private int skewBlocks_number = -1; private int extendedHeaderBlocks_number = -1; private int externalHeaderBlocks_number = -1; private int generalTrailer_blocks = -1; // -------------------------------------------------------- // ------------General header 2 data-------------- private String segd_revision = null; private int generalHeaderBlock_number = -1; private int sequence_number = -1; private File file = null; // -------------------------------------------------------- // ------------General header 3 data-------------- // --------------------------------------------------------- private AdditionalGeneralHeader[] additionalGeneralHeaders = null; private ScanType[] scanTypes = null; //Extended header data private short[][] extendedHeadersData = null; //External header data private short[][] externalHeadersData = null; private FileInputStreamPositioned inputStream= null; public SegdRecord(File file) throws FileNotFoundException, IOException { this.file = file; } public int getFileNumber(){ return fileNumber; } public Format getFormat(){ return format; } public short[] getGeneralConstants(){ return general_constants; } public short getAdditionalGeneralHeaderBlocksNumber(){ return additionalGeneralHeaderBlocksNumber; } public Date getDate(){ return date; } public int getManufacturerCode(){ return manufacturer_code; } public int getManufacturerSerialNnum(){ return manufacturer_serial_num; } public double getBaseScanInterval(){ return base_scan_interval; } public Polarity getPolatity(){ return polarity; } public RecordType getRecordtype(){ return recordType; } public double getRecordLength(){ return recordLength; } public int getScanTypesPerRecord(){ return scanTypes_per_record; } public int getChannelSetsPerScanType(){ return channelSets_per_scanType; } public int getSkewBlocksNumber(){ return skewBlocks_number; } public int getExtendedHeaderBlocksNumber(){ return extendedHeaderBlocks_number; } public int getExternalHeaderBlocksNumber(){ return externalHeaderBlocks_number; } public int getGeneralTrailerBlocks(){ return generalTrailer_blocks; } public String getSegdRevision(){ return segd_revision; } public int generalHeaderBlock_number(){ return generalHeaderBlock_number; } public int getSequenceNumber(){ return sequence_number; } public AdditionalGeneralHeader[] getAdditionalGeneralHeaders(){ return additionalGeneralHeaders; } public ScanType[] getScanTypes(){ return scanTypes; } public short[][] getExtendedHeadersData(){ return extendedHeadersData; } public short[][] getExternalHeadersData(){ return externalHeadersData; } public void readHeaders() throws IOException{ inputStream = new FileInputStreamPositioned(new FileInputStream(file)); readHeaders(new DataInputStream(inputStream)); inputStream.close(); } private void readHeaders(DataInput inStream) throws IOException { try { readHeader1(inStream); } catch (IOException e) { logger.error("IOException:", e); } catch (SegdException e) { logger.error("SegdException:", e); } readHeader2(inStream); additionalGeneralHeaders = new AdditionalGeneralHeader[additionalGeneralHeaderBlocksNumber-1]; for(int i=1; i<additionalGeneralHeaderBlocksNumber; i++){ AdditionalGeneralHeader additionalGeneralHeader = new AdditionalGeneralHeader(); additionalGeneralHeader.read(inStream); additionalGeneralHeaders[i-1]=additionalGeneralHeader; } scanTypes = new ScanType[scanTypes_per_record]; for(int i=0; i<scanTypes_per_record; i++){ ScanType scanType = new ScanType(i, this); scanType.read(inStream); scanTypes[i]=scanType; } extendedHeadersData = new short[extendedHeaderBlocks_number][32]; for(int i = 0; i < extendedHeaderBlocks_number; i++){ readExtendedHeader(inStream, extendedHeadersData[i]); } externalHeadersData = new short[externalHeaderBlocks_number][32]; for(int i = 0; i < externalHeaderBlocks_number; i++){ readExternalHeader(inStream, externalHeadersData[i]); } //Read traces for(ScanType scanType: scanTypes){ for(ChannelSet channelSet: scanType.getChannelSets()){ for(int i = 0; i<channelSet.getChannels_in_set(); i++){ //System.out.println("Trace " + i); Trace trace = new Trace(this); trace.readHeader(inStream); trace.setDataOffset(getPosition()); trace.readData(inStream); //inStream.skipBytes(trace.getSamplesNumber()*4); //skip place for data channelSet.addTrace(trace); } } } } public void readHeader1(DataInput inStream) throws IOException, SegdException { // BYTES 1 -2 file number; if 'FFFF', see general header block #3 try { short[] check = { 0xFF, 0xFF }; fileNumber = getDataValue(getSections( readBytes(inStream, 2, check), 4), 10); } catch (CheckFailedException e) { // Does nothing logger.error("CheckFailedException:", e); } try { int formatCode = getDataValue(getSections(readBytes(inStream, 2, null), 4), 10); switch (formatCode) { case 15: format = Format.BINARY_MULTIPLEXED_20_BIT; break; case 22: format = Format.QUATERNARY_MULTIPLEXED_8_BIT; break; case 24: format = Format.QUATERNARY_MULTIPLEXED_16_BIT; break; case 36: format = Format.COMPLIMENT_2_INTEGER_MULTIPLEXED_24_BIT; break; case 38: format = Format.COMPLIMENT_2_INTEGER_MULTIPLEXED_32_BIT; break; case 42: format = Format.HEXADECIMAL_MULTIPLEXED_8_BIT; break; case 44: format = Format.HEXADECIMAL_MULTIPLEXED_16_BIT; break; case 48: format = Format.HEXADECIMAL_MULTIPLEXED_32_BIT; break; case 58: format = Format.IEEE_MULTIPLEXED_32_BIT; break; case 8015: format = Format.BINARY_DEMUX_20_BIT; break; case 8022: format = Format.QUATERNARY_DEMUX_8_BIT; break; case 8024: format = Format.QUATERNARY_DEMUX_16_BIT; break; case 8036: format = Format.COMPLIMENT_2_INTEGER_DEMUX_24_BIT; break; case 8038: format = Format.COMPLIMENT_2_INTEGER_DEMUX_32_BIT; break; case 8042: format = Format.HEXADECIMAL_DEMUX_8_BIT; break; case 8044: format = Format.HEXADECIMAL_DEMUX_16_BIT; break; case 8048: format = Format.HEXADECIMAL_DEMUX_32_BIT; break; case 8058: format = Format.IEEE_DEMUX_32_BIT; break; default: format = null; throw new SegdException("Wrong format code: " + formatCode); } } catch (CheckFailedException e) { logger.error("CheckFailedException:", e); } try { general_constants = getSections(readBytes(inStream, 6, null), 4); int year = getDataValue(getSections(readBytes(inStream, 1, null), 4), 10); short byte12 = readBytes(inStream, 1, null)[0]; additionalGeneralHeaderBlocksNumber = (short) (byte12 >>> 4); short[] day_digits = new short[3]; day_digits[0] = (short) (byte12 & 0xF); short[] day_digits_byte13 = getSections(readBytes(inStream, 1, null), 4); day_digits[1] = day_digits_byte13[0]; day_digits[2] = day_digits_byte13[1]; int jDay = getDataValue(day_digits, 10); if(jDay>366) throw new SegdException("Wrong Julian day: " + jDay); int hour = getDataValue(getSections(readBytes(inStream, 1, null), 4), 10); if(hour>24) throw new SegdException("Wrong hour: " + hour); int minute = getDataValue(getSections(readBytes(inStream, 1, null), 4), 10); if(minute>60) throw new SegdException("Wrong minute: " + minute); int second = getDataValue(getSections(readBytes(inStream, 1, null), 4), 10); if(second>60) throw new SegdException("Wrong second: " + second); date = new Date(TimeInterval.getTime(year > 50 ? 1900 + year: 2000 + year, jDay, hour, minute, second, 0)); manufacturer_code = getDataValue(getSections(readBytes(inStream, 1, null), 4), 10); manufacturer_serial_num = getDataValue(getSections(readBytes(inStream, 2, null), 4), 10); inStream.skipBytes(3); // not used base_scan_interval = readBytes(inStream, 1, null)[0] / 16; int byte24 = readBytes(inStream, 1, null)[0]; byte24 = byte24 >>> 4; switch (byte24) { case 0: polarity = Polarity.UNTESTED; break; case 1: polarity = Polarity.ZERO; break; case 2: polarity = Polarity.DEGREES_45; break; case 3: polarity = Polarity.DEGREES_90; break; case 4: polarity = Polarity.DEGREES_135; break; case 5: polarity = Polarity.DEGREES_180; break; case 6: polarity = Polarity.DEGREES_225; break; case 7: polarity = Polarity.DEGREES_270; break; case 8: polarity = Polarity.DEGREES_315; break; case 12: polarity = Polarity.DEGREES_315; break; default: polarity = null; throw new SegdException("Wrong polarity: " + polarity); } inStream.skipBytes(1); // not used } catch (CheckFailedException e) { logger.error("CheckFailedException:", e); } try { short byte26 = readBytes(inStream, 1, null)[0]; short recordTypeCode = (short) (byte26 >>> 4); switch (recordTypeCode) { case 2: recordType = RecordType.TEST_RECORD; break; case 4: recordType = RecordType.PARALLEL_CHANNEL_TEST; break; case 6: recordType = RecordType.DIRECT_CHANNEL_TEST; break; case 8: recordType = RecordType.NORMAL_RECORD; break; case 1: recordType = RecordType.OTHER; break; default: recordType = null; throw new SegdException("Wrong record type: " + recordType); } short[] record_length_digits = new short[3]; record_length_digits[0] = (short) (byte26 & 0xF); short[] record_length_digits_byte27 = getSections(readBytes(inStream, 1, null), 4); record_length_digits[1] = record_length_digits_byte27[0]; record_length_digits[2] = record_length_digits_byte27[1]; if(record_length_digits[0]==0xF && record_length_digits[1]==0xF && record_length_digits[2]==0xF){ throw new CheckFailedException(); } recordLength = getDataValue(record_length_digits, 10)/10.0; } catch (CheckFailedException e) { //see Extended Record length, bytes 15-17 General Header block #2 logger.error("CheckFailedException:", e); } try { scanTypes_per_record = getDataValue(getSections(readBytes(inStream, 1, null), 4), 10); short[] check = {0xFF}; channelSets_per_scanType = getDataValue(getSections(readBytes(inStream, 1, check), 4), 10); }catch (CheckFailedException e) { //see Extended channelSet/ScanTypes logger.error("CheckFailedException:", e); } try { skewBlocks_number = getDataValue(getSections(readBytes(inStream, 1, null), 4), 10); short[] check = {0xFF}; extendedHeaderBlocks_number = getDataValue(getSections(readBytes(inStream, 1, check), 4), 10); }catch (CheckFailedException e) { //see bytes 6-7 of General Header block #2 logger.error("CheckFailedException:", e); } try { short[] check = {0xFF}; externalHeaderBlocks_number = getDataValue(getSections(readBytes(inStream, 1, check), 4), 10); }catch (CheckFailedException e) { //see bytes 8-9 of General Header block #2 logger.error("CheckFailedException:", e); } } private void readHeader2(DataInput inStream) throws IOException { try { if(fileNumber == -1){ fileNumber = getDataValue(getSections(readBytes(inStream, 3, null), 1), 2); } else { inStream.skipBytes(3); } if(channelSets_per_scanType == -1){ channelSets_per_scanType = readShorts(inStream, 1)[0]; } else { inStream.skipBytes(2); } if(extendedHeaderBlocks_number == -1){ extendedHeaderBlocks_number = readShorts(inStream, 1)[0]; } else { inStream.skipBytes(2); } if(externalHeaderBlocks_number == -1){ externalHeaderBlocks_number = readShorts(inStream, 1)[0]; } else { inStream.skipBytes(2); } inStream.skipBytes(1); //not used segd_revision = readBytes(inStream, 1, null)[0] + "." + readBytes(inStream, 1, null)[0]; generalTrailer_blocks = readShorts(inStream, 1)[0]; if(recordLength == -1){ recordLength = getDataValue(getSections(readBytes(inStream, 3, null), 1), 2); } else { inStream.skipBytes(3); } inStream.skipBytes(1); //not used generalHeaderBlock_number = readBytes(inStream, 1, null)[0]; inStream.skipBytes(1); //not used sequence_number = readShorts(inStream, 1)[0]; inStream.skipBytes(10); //not used } catch (CheckFailedException e) { //Do nothing logger.error("CheckFailedException:", e); } catch (SegdException e) { logger.error("SegdException:", e); } } private void readExtendedHeader(DataInput inStream, short[] data) throws IOException{ try { data=readBytes(inStream, 32, null); } catch (CheckFailedException e) { logger.error("CheckFailedException:", e); } catch (SegdException e) { logger.error("SegdException:", e); } } private void readExternalHeader(DataInput inStream, short[] data) throws IOException{ try { data=readBytes(inStream, 32, null); } catch (CheckFailedException e) { logger.error("CheckFailedException:", e); } catch (SegdException e) { logger.error("SegdException:", e); } } public long getPosition(){ return inputStream.getPosition(); } static short[] readBytes(DataInput inStream, int byteCount, short[] check) throws IOException, SegdException, CheckFailedException { short[] ret = new short[byteCount]; for (int i = 0; i < byteCount; i++) { ret[i] = (short)inStream.readUnsignedByte(); } if (check != null) { if (check.length != ret.length) { throw new SegdException( "Check array size should be equal tested array size"); } for (int j = 0; j < ret.length; j++) { if (ret[j] != check[j]) { return ret; } } throw new CheckFailedException(); } return ret; } static int[] readShorts(DataInput inStream, int shortCount) throws IOException { int[] ret = new int[shortCount]; for (int i = 0; i < shortCount; i++) { ret[i] = inStream.readUnsignedShort(); } return ret; } static int readUnsignedTriple(DataInput inStream) throws IOException { int ret = 0; try { short[] read = readBytes(inStream, 3,null); ret = read[2]|(read[1]<<8)|(read[0]<<16); } catch (CheckFailedException e) { logger.error("CheckFailedException:", e); } catch (SegdException e) { logger.error("SegdException:", e); } return ret; } static int readSignedTriple(DataInput inStream) throws IOException { int[] read = new int[3]; int ret = 0; read[0] = inStream.readByte(); read[1] = inStream.readUnsignedByte(); read[2] = inStream.readUnsignedByte(); ret = read[2]|(read[1]<<8)|(read[0]<<16); return ret; } static short[] getSections(short[] bytes, int blockLength) { int blocksOnByte = 8 / blockLength; int arrayLength = bytes.length * blocksOnByte; int mask = 1; for (int i = 1; i < blockLength; i++) { mask = mask + (int) Math.pow(2, i); } short[] ret = new short[arrayLength]; for (int i = 0; i < bytes.length; i++) { int byteValue = bytes[i]; for (int j = 0; j < blocksOnByte; j++) { ret[(i * blocksOnByte) + blocksOnByte - j - 1] = new Integer( byteValue & mask).byteValue(); byteValue = byteValue >>> blockLength; } } return ret; } static int getDataValue(short[] digits, int base) { int ret = 0; for (int i = 0; i < digits.length; i++) { if (digits[i] >= base) { System.out.println("digit value is more than base"); return -1; } ret = ret + digits[i] * (int) Math.pow(base, (digits.length - i - 1)); } return ret; } public String toString() { String additionalHeadersStr = ""; for(AdditionalGeneralHeader agh: additionalGeneralHeaders){ additionalHeadersStr = additionalHeadersStr+agh.toString(); } String scanTypesStr = ""; for(ScanType st: scanTypes){ scanTypesStr = scanTypesStr+st.toString(); } String extHeadersStr = ""; if(extendedHeadersData.length>0){ extHeadersStr = extHeadersStr+ "\nExtended headers:"; for(short[] extendedHeaderData: extendedHeadersData){ extHeadersStr = extHeadersStr+ "\n"+Arrays.toString(extendedHeaderData); } } if(externalHeadersData.length>0){ extHeadersStr = extHeadersStr+ "\nExternal headers:"; for(short[] externalHeaderData: externalHeadersData){ extHeadersStr = extHeadersStr+ "\n"+Arrays.toString(externalHeaderData); } } return "File number: " + fileNumber + "\nFormat: " + format +"\nGeneral constants: " + Arrays.toString(general_constants) +"\nNumber of additional General Header Blocks: " + additionalGeneralHeaderBlocksNumber +"\nDate: " + (date == null ? "null" : date) +"\nManufacturer code: " + manufacturer_code +"\nManufacturer serial number: "+ manufacturer_serial_num +"\nBase scan interval, msec: " + base_scan_interval +"\nPolarity: " + polarity +"\nRecord type: " + recordType +"\nRecord length, in 0.512 sec intervals: " + recordLength +"\nScan Types number per record: "+ scanTypes_per_record +"\nChannel Sets per Scan Type number: " + channelSets_per_scanType +"\nNumber of 32-bytes skew blocks: " + skewBlocks_number +"\nExtended header length, in 32 bytes blocks: " + extendedHeaderBlocks_number +"\nExternal header length, in 32 bytes blocks: " + externalHeaderBlocks_number +"\nSEGD revision: " + segd_revision +"\nGeneral trailer length, in 32 bytes blocks: " + generalTrailer_blocks +"\nGeneral header block number: " + generalHeaderBlock_number +"\nSequence number: " + sequence_number +additionalHeadersStr + extHeadersStr + scanTypesStr ; } public static void main(String[] args) { if (args.length != 1) { System.out.println("Usage: java SegdRecord [file_name]"); System.exit(1); } try { File file = new File(args[0]); SegdRecord rec = new SegdRecord(file); rec.readHeaders(); System.out.println(rec.toString()); } catch (FileNotFoundException e) { // TODO Auto-generated catch block logger.error("FileNotFoundException:", e); } catch (IOException e) { // TODO Auto-generated catch block logger.error("IOException:", e); } } } class CheckFailedException extends Exception { private static final long serialVersionUID = 1L; public CheckFailedException() { super(); } public CheckFailedException(String str) { super(str); } }