All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ucar.atd.dorade.DoradeDescriptor Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 1998-2018 University Corporation for Atmospheric Research/Unidata
 * See LICENSE for license information.
 */

package ucar.atd.dorade;

import ucar.nc2.constants.CDM;
import ucar.nc2.time.CalendarDateFormatter;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.util.Date;
import java.util.TimeZone;
import java.util.HashMap;

abstract class DoradeDescriptor {

  protected String descName;
  protected String expectedName;
  protected RandomAccessFile file;
  protected boolean littleEndianData;
  protected boolean verbose;

  protected static final TimeZone TZ_UTC = TimeZone.getTimeZone("UTC");
  private static boolean defaultVerboseState = false;
  // map from descriptor names to per-class default verbose states
  private static HashMap classVerboseStates = new HashMap<>();

  static class DescriptorException extends Exception {
    protected DescriptorException(String message) {
      super(message);
    }

    protected DescriptorException(Throwable cause) {
      super(cause);
    }
  }

  /**
   * Read and set the descriptor name, size, and endianness, and return the
   * entire contents of the descriptor (including the name and size) as a
   * byte array.  The file position will be left at the beginning of the next
   * descriptor (or at the end of file).
   *
   * @param file             the DORADE sweepfile, positioned at the beginning of a
   *                         descriptor
   * @param littleEndianData set to true iff the file contains little-endian
   *                         data
   * @param expectedName     the expected name for the descriptor being read
   * @throws DescriptorException for file read errors, descriptor name
   *                             mismatch, etc.
   */
  protected byte[] readDescriptor(RandomAccessFile file,
                                  boolean littleEndianData,
                                  String expectedName)
          throws DescriptorException {

    this.file = file;
    this.littleEndianData = littleEndianData;
    this.expectedName = expectedName;
    verbose = getDefaultVerboseState(expectedName);

    byte[] data;

    try {
      //
      // find the next descriptor with our expected name
      //
      findNext(file);

      //
      // keep track of the start of this descriptor
      //
      long startpos = file.getFilePointer();

      //
      // get the name and descriptor size
      //
      byte[] header = new byte[8];
      file.readFully(header);
      descName = new String(header, 0, 4, CDM.utf8Charset);
      int size = grabInt(header, 4);

      //
      // now back up to the start of the descriptor and read the entire
      // thing into a byte array
      //
      file.seek(startpos);

      data = new byte[size];
      file.readFully(data);
    } catch (java.io.IOException ex) {
      throw new DescriptorException(ex);
    }

    //
    // now check the name we got against the expected name
    //
    if (!descName.equals(expectedName))
      throw new DescriptorException("Got descriptor name '" + descName +
              "' when expecting name '" +
              expectedName + "'");

    return data;
  }

  /**
   * Skip the current DORADE descriptor in the file, leaving the file position
   * at the beginning of the next descriptor (or at the end of file).
   *
   * @param file the DORADE sweepfile, positioned at the beginning of a
   *             descriptor
   * @throws java.io.IOException
   */
  protected static void skipDescriptor(RandomAccessFile file,
                                       boolean littleEndianData)
          throws DescriptorException, java.io.IOException {
    try {
      file.readFully(new byte[4]); // skip name
      byte[] lenBytes = new byte[4];
      file.readFully(lenBytes);
      int descLen = grabInt(lenBytes, 0, littleEndianData);
      file.readFully(new byte[descLen - 8]);
    } catch (java.io.EOFException eofex) {
      return; // just leave the file at EOF
    } catch (Exception ex) {
      throw new DescriptorException(ex);
    }
  }

  /**
   * Return the name of the DORADE descriptor at the current location
   * in the file.  The current location will not be changed.
   *
   * @param file the DORADE sweep file, positioned at the beginning of a
   *             descriptor
   * @return the name of the DORADE descriptor starting at the current
   * file position, or null if no descriptor name is available
   * @throws DescriptorException
   */
  protected static String peekName(RandomAccessFile file)
          throws DescriptorException {
    try {
      long filepos = file.getFilePointer();
      byte[] nameBytes = new byte[4];
      if (file.read(nameBytes) == -1)
        return null;  // EOF
      file.seek(filepos);
      return new String(nameBytes, CDM.utf8Charset);

    } catch (IOException ex) {
      throw new DescriptorException(ex);
    }
  }

  /**
   * Determine if the given DORADE sweepfile contains little-endian data
   * (in violation of the DORADE definition...).
   *
   * @param file the DORADE sweepfile,
   * @return true iff the file contains little-endian data
   * @throws DescriptorException
   */
  public static boolean sweepfileIsLittleEndian(RandomAccessFile file)
          throws DescriptorException {
    int descLen;
    try {
      file.seek(0);
      //
      // skip the 4-byte descriptor name
      //
      byte[] bytes = new byte[4];
      file.readFully(bytes);
      //
      // get the descriptor length
      //
      descLen = file.readInt();
      file.seek(0);
    } catch (Exception ex) {
      throw new DescriptorException(ex);
    }
    return (descLen < 0 || descLen > 0xffffff);
  }

  /**
   * Unpack a two-byte integer from the given byte array.
   *
   * @param bytes  byte array to be read
   * @param offset number of bytes to skip in the byte array before reading
   * @return the unpacked short value
   */
  protected short grabShort(byte[] bytes, int offset) {
    int ndx0 = offset + (littleEndianData ? 1 : 0);
    int ndx1 = offset + (littleEndianData ? 0 : 1);
    // careful that we only allow sign extension on the highest order byte
    return (short) (bytes[ndx0] << 8 | (bytes[ndx1] & 0xff));
  }

  /**
   * Unpack a four-byte integer from the given byte array.
   *
   * @param bytes            byte array to be read
   * @param offset           number of bytes to skip in the byte array before reading
   * @param littleEndianData true iff the byte array contains little-endian
   *                         data
   * @return the unpacked integer value
   */
  protected static int grabInt(byte[] bytes, int offset,
                               boolean littleEndianData) {
    int ndx0 = offset + (littleEndianData ? 3 : 0);
    int ndx1 = offset + (littleEndianData ? 2 : 1);
    int ndx2 = offset + (littleEndianData ? 1 : 2);
    int ndx3 = offset + (littleEndianData ? 0 : 3);

    // careful that we only allow sign extension on the highest order byte
    return (bytes[ndx0] << 24 |
            (bytes[ndx1] & 0xff) << 16 |
            (bytes[ndx2] & 0xff) << 8 |
            (bytes[ndx3] & 0xff));
  }

  /**
   * Unpack a four-byte integer from the given byte array.
   *
   * @param bytes  byte array to be read
   * @param offset number of bytes to skip in the byte array before reading
   * @return the unpacked integer value
   */
  protected int grabInt(byte[] bytes, int offset) {
    return grabInt(bytes, offset, littleEndianData);
  }

  /**
   * Unpack a four-byte IEEE float from the given byte array.
   *
   * @param bytes  byte array to be read
   * @param offset number of bytes to skip in the byte array before reading
   * @return the unpacked float value
   */
  protected float grabFloat(byte[] bytes, int offset)
          throws DescriptorException {
    try {
      byte[] src;
      if (littleEndianData) {
        src = new byte[4];
        src[0] = bytes[offset + 3];
        src[1] = bytes[offset + 2];
        src[2] = bytes[offset + 1];
        src[3] = bytes[offset];
        offset = 0;
      } else {
        src = bytes;
      }
      DataInputStream stream =
              new DataInputStream(new ByteArrayInputStream(src, offset, 4));
      return stream.readFloat();
    } catch (Exception ex) {
      throw new DescriptorException(ex);
    }
  }

  /**
   * Unpack an eight-byte IEEE float from the given byte array.
   *
   * @param bytes  byte array to be read
   * @param offset number of bytes to skip in the byte array before reading
   * @return the unpacked double value
   */
  protected double grabDouble(byte[] bytes, int offset)
          throws DescriptorException {
    try {
      byte[] src;
      if (littleEndianData) {
        src = new byte[8];
        src[0] = bytes[offset + 7];
        src[1] = bytes[offset + 6];
        src[2] = bytes[offset + 5];
        src[3] = bytes[offset + 4];
        src[4] = bytes[offset + 3];
        src[5] = bytes[offset + 2];
        src[6] = bytes[offset + 1];
        src[7] = bytes[offset];
        offset = 0;
      } else {
        src = bytes;
      }
      DataInputStream stream =
              new DataInputStream(new ByteArrayInputStream(src, offset, 8));
      return stream.readDouble();
    } catch (Exception ex) {
      throw new DescriptorException(ex);
    }
  }


  protected static long findNextWithName(String expectedName,
                                         RandomAccessFile file,
                                         boolean littleEndianData)
          throws DescriptorException, java.io.IOException {

    //
    // Skip forward through the file until we find a descriptor with
    // the expected name
    //
    String descName;
    while ((descName = peekName(file)) != null) {
      if (descName.equals(expectedName)) {
        try {
          return file.getFilePointer();
        } catch (java.io.IOException ex) {
          throw new DescriptorException(ex);
        }
      }
      skipDescriptor(file, littleEndianData);
    }
    throw new DescriptorException("Expected " + expectedName +
            " descriptor not found!");
  }

  protected long findNext(RandomAccessFile file)
          throws DescriptorException, java.io.IOException {
    return findNextWithName(expectedName, file, littleEndianData);
  }


  /**
   * Return a string with a reasonable and complete representation of the
   * given Date, shown in UTC.
   *
   * @param date Date to be represented
   * @return a string containing the representation of the date
   */
  public static String formatDate(Date date) {
    return CalendarDateFormatter.toDateTimeString(date);
  }

  /**
   * Get the default verbose state for new DoradeDescriptor-s.
   */
  public static boolean getDefaultVerboseState() {
    return defaultVerboseState;
  }

  /**
   * Set the default verbose state for new DoradeDescriptor-s.
   *
   * @param verbose the new default verbose state
   */
  public static void setDefaultVerboseState(boolean verbose) {
    defaultVerboseState = verbose;
    classVerboseStates.clear();
  }

  /**
   * Get the default verbose state for new DoradeDescriptor-s
   * of the given name.
   *
   * @param descriptorName the descriptor name for which the new default
   *                       verbose state will apply
   */
  public static boolean getDefaultVerboseState(String descriptorName) {
    Boolean classVerboseState = classVerboseStates.get(descriptorName.toUpperCase());
    if (classVerboseState != null)
      return classVerboseState;
    else
      return defaultVerboseState;
  }

  /**
   * Set the default verbose state for new DoradeDescriptor-s
   * of the given name.
   *
   * @param descriptorName the descriptor name for which the new default
   *                       verbose state will apply
   * @param verbose        the new default verbose state
   */
  public static void setDefaultVerboseState(String descriptorName,
                                            boolean verbose) {
    classVerboseStates.put(descriptorName.toUpperCase(), verbose);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy