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

ucar.nc2.iosp.nids.Nidsheader Maven / Gradle / Ivy

Go to download

The NetCDF-Java Library is a Java interface to NetCDF files, as well as to many other types of scientific data formats.

There is a newer version: 4.3.22
Show newest version
/*
 * Copyright 1998-2009 University Corporation for Atmospheric Research/Unidata
 *
 * Portions of this software were developed by the Unidata Program at the
 * University Corporation for Atmospheric Research.
 *
 * Access and use of this software shall impose the following obligations
 * and understandings on the user. The user is granted the right, without
 * any fee or cost, to use, copy, modify, alter, enhance and distribute
 * this software, and any derivative works thereof, and its supporting
 * documentation for any purpose whatsoever, provided that this entire
 * notice appears in all copies of the software, derivative works and
 * supporting documentation.  Further, UCAR requests that the user credit
 * UCAR/Unidata in any publications that result from the use of this
 * software or in any product that includes this software. The names UCAR
 * and/or Unidata, however, may not be used in any advertising or publicity
 * to endorse or promote any products or commercial entity unless specific
 * written permission is obtained from UCAR/Unidata. The user also
 * understands that UCAR/Unidata is not obligated to provide the user with
 * any support, consulting, training or assistance of any kind with regard
 * to the use, operation and performance of this software nor to provide
 * the user with any updates, revisions, new versions or "bug fixes."
 *
 * THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 * WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
 */
package ucar.nc2.iosp.nids;

import ucar.ma2.*;
import ucar.ma2.DataType;
import ucar.nc2.Attribute;
import ucar.nc2.*;
import ucar.nc2.iosp.nexrad2.NexradStationDB;
import ucar.nc2.iosp.IospHelper;
import ucar.nc2.constants.AxisType;
import ucar.nc2.constants.*;
import ucar.nc2.units.DateFormatter;
import ucar.unidata.geoloc.projection.FlatEarth;
import ucar.unidata.geoloc.ProjectionImpl;
import ucar.unidata.io.bzip2.CBZip2InputStream;
import ucar.unidata.io.bzip2.BZip2ReadException;
import ucar.unidata.util.Parameter;

import java.io.*;
import java.nio.*;
import java.util.*;
import java.util.zip.*;

/**
 * This class reads in an NEXRAD level III and TDWR file.
 * most file need to go through the header part to have enough info to
 * construct the netcdf structure of the radar file
 *
 * @author caron
 */

class Nidsheader{
    final private static boolean useStationDB = false; // use station db for loactions
    static private org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Nidsheader.class);

    final static int  NEXR_PID_READ = 100;
    final static int  DEF_NUM_ELEMS = 640;   /* default num of elements to send         */
    final static int  DEF_NUM_LINES = 480;   /* default num of lines to send            */
    final static int  NEXR_FILE_READ = -1;   /* # flag to read entire NIDS file         */
    final static int  NEXR_DIR_READ = 356 ;  /* just enough bytes for NIDS directory    */
    final static int  READ_BUFFER_SIZE = 1;   /* # of image lines to buffer on read      */
    final static int  ZLIB_BUF_LEN = 4000;   /* max size of an uncompressed ZLIB buffer */
    byte Z_DEFLATED  = 8;
    byte DEF_WBITS  = 15;
    final static int   Other = 0;
    final static int   Base_Reflect = 1;
    final static int   Velocity = 2;
    final static int   Comp_Reflect = 3;
    final static int   Layer_Reflect_Avg = 4;
    final static int   Layer_Reflect_Max = 5;
    final static int   Echo_Tops = 6;
    final static int   Vert_Liquid = 7;
    final static int   Precip_1 = 8;
    final static int   Precip_3 = 9;
    final static int   Precip_Accum = 10;
    final static int   Precip_Array = 11;
    final static int   BaseReflect248 = 12;
    final static int   StrmRelMeanVel = 13;
    final static int   VAD = 14;
    final static int   SPECTRUM = 15;
    final static int   DigitalHybridReflect = 16;
    final static int   DigitalStormTotalPrecip = 17;
    final static int   Reflect1 = 18;
    final static int   Velocity1 = 19;
    final static int   SPECTRUM1 = 20;
    final static int   BaseReflectivityDR = 21;
    final static int   BaseVelocityDV = 22;
    final static int   EnhancedEcho_Tops = 23;
    final static int   DigitalVert_Liquid = 24;
    // message header block
    short mcode = 0;
    short mdate = 0;
    int mtime = 0;
    int mlength = 0;
    short msource = 0;
    short mdestId = 0;
    short mNumOfBlock = 0;
    // production dessciption block
    short divider = 0;
    double latitude = 0.0;
    double lat_min = 0.0;
    double lat_max = 0.0;
    double longitude = 0.0;
    double lon_min = 0.0;
    double lon_max = 0.0;

    double height = 0;
    short pcode = 0;
    short opmode = 0;
    short volumnScanPattern = 0;
    short sequenceNumber = 0;
    short volumeScanNumber = 0;
    short volumeScanDate = 0;
    int volumeScanTime = 0;
    short productDate = 0;
    int productTime = 0;
    short p1 = 0;
    short p2 = 0;
    short elevationNumber = 0;
    short p3 = 0;
    short [] threshold = new short[16];
    short p4 = 0;
    short p5 = 0;
    short p6 = 0;
    short p7 = 0;
    short p8 = 0;
    short p9 = 0;
    short p10 = 0;
    short numberOfMaps = 0;
    int offsetToSymbologyBlock = 0;
    int offsetToGraphicBlock = 0;
    int offsetToTabularBlock = 0;
    int block_length = 0;
    short number_layers = 0;
    String stationId;
    String stationName = "XXX";
    private boolean noHeader;

    DateFormatter formatter = new DateFormatter();

    /**
     * check if this file is a nids / tdwr file
     * @param raf    input file
     * @return  true  if valid
     */
    public boolean isValidFile( ucar.unidata.io.RandomAccessFile raf) {
        try
        {
            long t = raf.length();
            if(t == 0){
                throw new IOException("zero length file ");
            }
        }
        catch ( IOException e )
        {
            return( false );
        }

        try{
            int p = this.readWMO( raf );
            if( p == 0 ) return false; // not unidata radar mosiac gini file
        }
        catch ( IOException e )
        {
            return( false );
        }                                 
        return true;
    }

    /**
     * read the header of input file and parsing the WMO part
     * @param raf    input file
     * @return        1 if checking passing
     * @throws IOException
     */
    int readWMO(ucar.unidata.io.RandomAccessFile raf ) throws IOException
    {
        int pos = 0;
        //long     actualSize = 0;
        raf.seek(pos);
        int readLen = 35;
        int rc = 0;

        // Read in the contents of the NEXRAD Level III product head
        byte[] b = new byte[readLen];
        rc = raf.read(b);
        if ( rc != readLen )
        {
            // out.println(" error reading nids product header");
            return 0;
        }

        // new check
        int iarr2_1 = bytesToInt(b[0], b[1], false);
        int iarr2_16 = bytesToInt(b[30], b[31], false);
        int iarr2_10 = bytesToInt(b[18], b[19], false);
        int iarr2_7 = bytesToInt(b[12], b[13], false);
        if ( ( iarr2_1 == iarr2_16 ) &&
             ( ( iarr2_1 >=   16  ) && ( iarr2_1 <= 299) ) &&
             ( iarr2_10  ==   -1 ) &&
             ( iarr2_7   <    10000 ) )  {
             noHeader = true;
             return 1;

        }
        //Get product message header into a string for processing

        String pib = new String(b);
        if(  pib.indexOf("SDUS")!= -1){
            noHeader = false;
            return 1;
        } else if ( raf.getLocation().indexOf(".nids") != -1) {
            noHeader = true;
            return 1;
       // } else if(checkMsgHeader(raf) == 1) {
        //    noHeader = true;
       //     return 1;
        } else
            return 0;
    }

    /**
     * read the compressed data
     *
     * @param offset   offset of the compressed data
     * @param len      length of data to compress
     * @return         uncompressed byte array
     */
    public byte[] getUncompData(int offset, int len){
      if( len == 0 ) len = uncompdata.length - offset;
      byte[] data = new byte[len];
      System.arraycopy(uncompdata, offset, data, 0, len);
      return data;
    }
 //////////////////////////////////////////////////////////////////////////////////

    private ucar.unidata.io.RandomAccessFile raf;
    private ucar.nc2.NetcdfFile ncfile;
    //private PrintStream out = System.out;
    //private Vinfo myInfo;
    private String   cmemo, ctilt, ctitle, cunit, cname;
    public void setProperty( String name, String value) { }

    private   int numX ;
    private   int numX0;
    private   int numY ;
    private   int numY0;
    private   boolean isR = false;
    private byte[] uncompdata = null;

    /**
     * read and parse the header of the nids/tdwr file
     * @param raf       input file
     * @param ncfile    output file
     * @throws IOException
     */

    void read(ucar.unidata.io.RandomAccessFile raf, ucar.nc2.NetcdfFile ncfile ) throws IOException {

        int      hedsiz;                  /* NEXRAD header size            */
        int      rc;                      /* function return status        */
        int      hoff = 0;
        int      type;
        int      zlibed;
        boolean  isZ = false;
        int      encrypt;
        long     actualSize ;
        int      readLen ;
        int     p = readWMO( raf );
        this.ncfile = ncfile;
        actualSize = raf.length();
        int pos = 0;
        raf.seek(pos);

        // Read in the whole contents of the NEXRAD Level III product since
        // some product require to go through the whole file to build the  struct of file.

        readLen = (int)actualSize;

        byte[] b = new byte[readLen];
        rc = raf.read(b);
        if ( rc != readLen )
        {
            log.warn(" error reading nids product header "+raf.getLocation());
        }

        if( !noHeader ) {
        //Get product message header into a string for processing
            String pib = new String(b, 0, 100);
            type = 0;
            pos = pib.indexOf ( "\r\r\n" );
            while ( pos != -1 ) {
                hoff =  pos + 3;
                type++;
                pos = pib.indexOf ( "\r\r\n" , pos+1);
            }
            raf.seek(hoff);

            // Test the next two bytes to see if the image portion looks like
            // it is zlib-compressed.
            byte[] b2 = new byte[2];
            // byte[] b4 = new byte[4];
            System.arraycopy(b, hoff, b2, 0, 2);

            zlibed = isZlibHed( b2 );
            if ( zlibed == 0){
                encrypt = IsEncrypt( b2 );
                if(encrypt == 1){
                    log.error( "error reading encryted product "+raf.getLocation());
                    throw new IOException("unable to handle the product with encrypt code " + encrypt);
                }
            }
           // process product description for station ID
            byte[] b3 = new byte[3];
            //byte[] uncompdata = null;

            switch ( type ) {
              case 0:
                log.warn( "ReadNexrInfo:: Unable to seek to ID "+raf.getLocation());
                break;
              case 1:
              case 2:
              case 3:
              case 4:
                System.arraycopy(b, hoff - 6, b3, 0, 3);
                stationId  = new String(b3);
                try {
                  NexradStationDB.init(); // make sure database is initialized
                  NexradStationDB.Station station = NexradStationDB.get("K"+stationId);
                  if (station != null) {
                    stationName = station.name;
                  }
                } catch (IOException ioe) {
                  log.error("NexradStationDB.init "+raf.getLocation(), ioe);
                }
                break;

              default:
                break;
            }

        if ( zlibed == 1 ) {
              isZ = true;
              uncompdata = GetZlibedNexr( b, readLen,  hoff );
              //uncompdata = Nidsiosp.readCompData(hoff, 160) ;
              if ( uncompdata == null ) {
                log.warn( "ReadNexrInfo: error uncompressing image " +raf.getLocation());
              }
        }
        else {
             uncompdata = new byte[b.length-hoff];
             System.arraycopy(b, hoff, uncompdata, 0, b.length- hoff);
        }
    } else {
        uncompdata = new byte[b.length];
        System.arraycopy(b, 0, uncompdata, 0, b.length);
        // stationId  = "YYY";
    }
    byte[] b2 = new byte[2];
    ByteBuffer bos = ByteBuffer.wrap(uncompdata);
    rc = read_msghead( bos, 0 );
    hedsiz = 18;
    Pinfo pinfo = read_proddesc( bos, hedsiz );

    bos.position();
    hedsiz += 102;



    // Set product-dependent information
    int prod_type = code_typelookup(pinfo.pcode);
    setProductInfo(prod_type, pinfo );

    //int windb = 0;
    int pcode1Number = 0;
    int pcode2Number = 0;
    int pcode8Number = 0;
    int pcode4Number = 0;
    int pcode5Number = 0;
    int pcode10Number = 0;
    int pcode6Number = 0;
    int pcode25Number = 0;
    int pcode12Number = 0;
    int pcode13Number = 0;
    int pcode14Number = 0;
    int pcode15Number = 0;
    int pcode16Number = 0;
    int pcode19Number = 0;
    int pcode20Number = 0;
    int pkcode1Doff[] = null;
    int pkcode2Doff[] = null;
    int pkcode8Doff[] = null;
    int pkcode1Size[] = null;
    int pkcode2Size[] = null;
    int pkcode8Size[] = null;
    int pkcode4Doff[] = null;
    int pkcode5Doff[] = null;
    int pkcode10Doff[] = null;
    int pkcode10Dlen[] = null;
    int pkcode6Doff[] = null;
    int pkcode6Dlen[] = null;
    int pkcode25Doff[] = null;
    int pkcode12Doff[] = null;
    int pkcode13Doff[] = null;
    int pkcode14Doff[] = null;
    int pkcode12Dlen[] = null;
    int pkcode13Dlen[] = null;
    int pkcode14Dlen[] = null;
    int pkcode15Dlen[] = null;
    int pkcode15Doff[] = null;
    int pkcode16Dlen[] = null;
    int pkcode16Doff[] = null;
    int pkcode19Dlen[] = null;
    int pkcode19Doff[] = null;
    int pkcode20Dlen[] = null;
    int pkcode20Doff[] = null;
    // Get product symbology header (needed to get image shape)
    ifloop: if ( pinfo.offsetToSymbologyBlock != 0 ) {

      // Symbology header
      if(pinfo.p8 == 1) {
          // TDWR data and the symbology is compressed
          int size = shortsToInt(pinfo.p9,  pinfo.p10, false);
          uncompdata = uncompressed(bos, hedsiz, size);
          bos = ByteBuffer.wrap(uncompdata);
      }

      Sinfo sinfo = read_dividlen( bos, hedsiz );
      if( rc == 0 || pinfo.divider != -1 )
      {
          log.warn( "error in product symbology header "+raf.getLocation());
      }

      if(sinfo.id != 1)
      {
          if(pinfo.pcode == 82) {
              read_SATab( bos, hedsiz );
          }
          break ifloop;

      }
      hedsiz += 10;

      // Symbology layer
      int klayer = pinfo.offsetToSymbologyBlock*2 + 10;
      for(int i=0; i obuff.length) {
                byte[] temp = obuff;
                obuff = new byte[temp.length * 2];
                System.arraycopy(temp, 0, obuff, 0, temp.length);
              }
              System.arraycopy(ubuff, 0, obuff, total, nread);
              total += nread;
            }
            if (obuff.length >= 0)
              System.arraycopy(obuff, 0, out, offset, total);
          } catch (BZip2ReadException ioe) {
            log.warn("Nexrad2IOSP.uncompress "+raf.getLocation(), ioe);
        }

        return out;

    }

    /**
     * convert two short into a integer
     * @param s1            short one
     * @param s2            short two
     * @param swapBytes      if swap bytes
     * @return
     */
    public static int shortsToInt(short s1, short s2, boolean swapBytes) {
       byte[] b = new byte[4];
       b[0] = (byte) (s1 >>> 8);
       b[1] = (byte) (s1 >>> 0);
       b[2] =  (byte) (s2 >>> 8);
       b[3] =  (byte) (s2 >>> 0);
       return bytesToInt(b, false);
    }

    /**
     * convert bytes into integer
     * @param bytes           bytes array
     * @param swapBytes       if need to swap
     * @return
     */
    public static int bytesToInt(byte [] bytes, boolean swapBytes) {
        byte a = bytes[0];
        byte b = bytes[1];
        byte c = bytes[2];
        byte d = bytes[3];
        if (swapBytes) {
            return ((a & 0xff) ) +
                ((b & 0xff) << 8 ) +
                ((c & 0xff) << 16 ) +
                ((d & 0xff) << 24);
        } else {
            return ((a & 0xff) << 24 ) +
                ((b & 0xff) << 16 ) +
                ((c & 0xff) << 8 ) +
                ((d & 0xff) );
        }
    }


      /*
      ** Name:       read_dividlen
      **
      ** Purpose:    Read divider ID header from NEXRAD Level III product
      **
      */
    Sinfo read_dividlen( ByteBuffer buf, int offset  )
    {
        int off = offset;
        byte[] b2 = new byte[2];
        byte[] b4 = new byte[4];
        short D_divider;
        short D_id;
        Short tShort ;

        buf.position(offset);
        buf.get(b2, 0, 2);
        tShort = (Short)convert(b2, DataType.SHORT, -1);
        D_divider  = tShort.shortValue();
        buf.get(b2, 0, 2);
        D_id  = (short)getInt(b2, 2);
        buf.get(b4, 0, 4);
        block_length  = getInt(b4, 4);
        buf.get(b2, 0, 2);
        number_layers  = (short)getInt(b2, 2);
        off = off + 10;

        return new Sinfo ( D_divider, D_id, block_length, number_layers);

    }

    void read_SATab( ByteBuffer buf, int offset  )
    {

          byte[] b2 = new byte[2];

          short B_divider;
          short numPages;
          short numChars;
          short E_divider;
          Short tShort ;

          buf.position(offset);
          buf.get(b2, 0, 2);
          tShort = (Short)convert(b2, DataType.SHORT, -1);
          B_divider  = tShort.shortValue();
          if(B_divider != -1){
             log.warn( "error reading stand alone tab message "+raf.getLocation());
          }
          buf.get(b2, 0, 2);
          numPages = (Short)convert(b2, DataType.SHORT, -1);
          int ppos =  buf.position();
          for(int i = 0; i < numPages; i++){
            buf.get(b2, 0, 2);
            while(getInt(b2, 2) != -1) {
                numChars  = (short)getInt(b2, 2);
                if(numChars < 0){
                    break;
                }
                byte[] tmp = new byte[numChars];
                buf.get(tmp);
                String text = new String(tmp);
                buf.get(b2, 0, 2);
            }
          }
          ArrayList dims =  new ArrayList();
          Dimension tbDim = new Dimension("pageNumber", numPages);
          ncfile.addDimension( null, tbDim);
          dims.add( tbDim);
          Variable ppage = new Variable(ncfile, null, null, "TabMessagePage");
          ppage.setDimensions(dims);
          ppage.setDataType(DataType.STRING);
          ppage.addAttribute( new Attribute("long_name", "Stand Alone Tabular Alphanumeric Product Message"));
          ncfile.addVariable(null, ppage);
          //ppage.setSPobject( new Vinfo (numPages, 0, tblen, 0, hoff, ppos, isR, false, null, null, 82, 0));
    }
    /*
    ** Name:       read_msghead
    **
    ** Purpose:    Read message header from NEXRAD Level III product
    **
    **
    */
    int read_msghead( ByteBuffer buf, int offset)
    {

        byte[] b2 = new byte[2];
        byte[] b4 = new byte[4];

        buf.position(0);
        buf.get(b2, 0, 2);
        mcode = (short) getInt(b2, 2);
        buf.get(b2, 0, 2);
        mdate = (short) getInt(b2, 2);
        buf.get(b4, 0, 4);
        mtime = getInt(b4, 4);
        buf.get(b4, 0, 4);
        java.util.Date volumnDate = getDate( mdate, mtime*1000);
        String dstring = formatter.toDateTimeStringISO(volumnDate);
        //out.println( "product date is " + dstring);
        mlength = getInt(b4, 4);
        buf.get(b2, 0, 2);
        msource = (short) getInt(b2, 2);
        if(stationId == null || stationName == null) {
          try {
              NexradStationDB.init(); // make sure database is initialized
              NexradStationDB.Station station = NexradStationDB.getByIdNumber("000"+Short.toString(msource));
              if (station != null) {
                stationId = station.id;
                stationName = station.name;
              }
            } catch (IOException ioe) {
              log.error("NexradStationDB.init "+raf.getLocation(), ioe);
            }
        }
        buf.get(b2, 0, 2);
        mdestId = (short) getInt(b2, 2);
        buf.get(b2, 0, 2);
        mNumOfBlock = (short) getInt(b2, 2);

        return 1;

    }

    /**
     * get unsigned integer from byte array
     * @param b
     * @param num
     * @return
     */
    int getUInt( byte[] b, int num )
    {
        int            base=1;
        int            i;
        int            word=0;

        int bv[] = new int[num];

        for (i = 0; i= 0; i-- ) {
            word += base * bv[i];
            base *= 256;
        }

        return word;
    }

    /**
     * get signed integer from bytes
     * @param b
     * @param num
     * @return
     */
    int getInt( byte[] b, int num )
    {
        int            base=1;
        int            i;
        int            word=0;

        int bv[] = new int[num];

        for (i = 0; i 127 )
        {
         bv[0] -= 128;
         base = -1;
        }
        /*
        ** Calculate the integer value of the byte sequence
        */

        for ( i = num-1; i >= 0; i-- ) {
        word += base * bv[i];
        base *= 256;
        }

        return word;

    }
   /***
    * Concatenate two bytes to a 32-bit int value.  a is the high order
    * byte in the resulting int representation, unless swapBytes is true, in
    * which b is the high order byte.
    * @param a high order byte
    * @param b low order byte
    * @param swapBytes byte order swap flag
    * @return 32-bit integer
    */

    public static int bytesToInt(byte a, byte b, boolean swapBytes) {
  		// again, high order bit is expressed left into 32-bit form
  		if (swapBytes) {
  			return (a & 0xff) + ((int)b << 8);
  		} else {
  			return ((int)a << 8) + (b & 0xff);
  		}
    }

    /**
     * convert unsigned byte to short
     * @param b
     * @return
     */
    public short convertunsignedByte2Short(byte b)
    {
        return (short)((b<0)? (short)b + 256 : (short)b);
    }

    /**
     *  convert short to unsigned integer
     * @param b
     * @return
     */
    public int convertShort2unsignedInt(short b)
    {
        return (b<0)? (-1)*b + 32768 : b;
    }

    /**
     * get jave date
     * @param julianDays
     * @param msecs
     * @return
     */
    static public java.util.Date getDate(int julianDays, int msecs) {
        long total = ((long) (julianDays - 1)) * 24 * 3600 * 1000 + msecs;
        return new Date( total);
    }

    /*
    ** Name:       read_proddesc
    **
    ** Purpose:    Read product description header from NEXRAD Level III product
    **
    **
    */
    Pinfo read_proddesc(  ByteBuffer buf, int offset ){
        byte[] b2 = new byte[2];
        byte[] b4 = new byte[4];
        int off = offset;
        Short tShort;
        Integer tInt;
        //Double tDouble = null;

        /* thredds global att */
        ncfile.addAttribute(null, new Attribute("title", "Nexrad Level 3 Data"));
        ncfile.addAttribute(null, new Attribute("keywords", "WSR-88D; NIDS"));
        ncfile.addAttribute(null, new Attribute("creator_name", "NOAA/NWS"));
        ncfile.addAttribute(null, new Attribute("creator_url", "http://www.ncdc.noaa.gov/oa/radar/radarproducts.html"));
        ncfile.addAttribute(null, new Attribute("naming_authority", "NOAA/NCDC"));


        //      ncfile.addAttribute(null, new Attribute("keywords_vocabulary", cname));
        //out.println( "offset of buffer is " + off);
        buf.position(offset);
        buf.get(b2, 0, 2);
        tShort = (Short)convert(b2, DataType.SHORT, -1);
        divider  =  tShort.shortValue();
        ncfile.addAttribute(null, new Attribute("Divider", tShort));

        buf.get(b4, 0, 4);
        tInt = (Integer)convert(b4, DataType.INT, -1);
        latitude = tInt.intValue()/ 1000.0;
        buf.get(b4, 0, 4);
        tInt = (Integer)convert(b4, DataType.INT, -1);
        longitude = tInt.intValue()/ 1000.0;
        buf.get(b2, 0, 2);
        height = getInt(b2, 2)*0.3048; // LOOK now in units of meters


        if (useStationDB) { // override by station table for more accuracy
        try {
          NexradStationDB.init(); // make sure database is initialized
          NexradStationDB.Station station = NexradStationDB.get("K"+stationId);
          if (station != null) {
            latitude = station.lat;
            longitude = station.lon;
            height = station.elev;
            stationName = station.name;
          }
        } catch (IOException ioe) {
          log.error("NexradStationDB.init "+raf.getLocation(), ioe);
        }
        }

        ncfile.addAttribute(null, new Attribute("RadarLatitude", new Double(latitude)));
        ncfile.addAttribute(null, new Attribute("RadarLongitude", new Double(longitude)));
        ncfile.addAttribute(null, new Attribute("RadarAltitude", new Double(height)));

        buf.get(b2, 0, 2);
        pcode = (short)getInt(b2, 2);
        ncfile.addAttribute(null, new Attribute("ProductStation", stationId));
        ncfile.addAttribute(null, new Attribute("ProductStationName", stationName));
        buf.get(b2, 0, 2);
        opmode = (short)getInt(b2, 2);
        ncfile.addAttribute(null, new Attribute("OperationalMode", new Short(opmode)));
        buf.get(b2, 0, 2);
        volumnScanPattern = (short)getInt(b2, 2);
        ncfile.addAttribute(null, new Attribute("VolumeCoveragePatternName", new Short(volumnScanPattern)));
        buf.get(b2, 0, 2);
        sequenceNumber = (short)getInt(b2, 2);
        ncfile.addAttribute(null, new Attribute("SequenceNumber", new Short(sequenceNumber)));
        buf.get(b2, 0, 2);
        volumeScanNumber = (short)getInt(b2, 2);
        ncfile.addAttribute(null, new Attribute("VolumeScanNumber", new Short(volumeScanNumber)));
        buf.get(b2, 0, 2);
        volumeScanDate = (short)getUInt(b2, 2);
        buf.get(b4, 0, 4);
        volumeScanTime = getUInt(b4, 4);
        buf.get(b2, 0, 2);
        productDate = (short)getUInt(b2, 2);
        buf.get(b4, 0, 4);
        productTime = getUInt(b4, 4);
        java.util.Date pDate = getDate( productDate, productTime*1000);
        String dstring = formatter.toDateTimeStringISO(pDate);
        ncfile.addAttribute(null, new Attribute("DateCreated", dstring));
        buf.get(b2, 0, 2);
        p1 = (short)getInt(b2, 2);
        buf.get(b2, 0, 2);
        p2 = (short)getInt(b2, 2);
        buf.get(b2, 0, 2);
        elevationNumber = (short)getInt(b2, 2);
        ncfile.addAttribute(null, new Attribute("ElevationNumber",new Short(elevationNumber)));
        buf.get(b2, 0, 2);
        p3 = (short)getInt(b2, 2);
        off += 40;
        if(pcode == 182 || pcode == 186 || pcode == 32
                || pcode == 94 || pcode == 99) {
          for(int i = 0; i< 16; i++) {
            buf.get(b2, 0, 2);
            threshold[i] = (short)bytesToInt(b2[0], b2[1], false);
          }
        }
        else {
          for(int i = 0; i< 16; i++) {
            buf.get(b2, 0, 2);
            threshold[i] = (short)getInt(b2, 2);
          }
        }
        off += 32;
        buf.get(b2, 0, 2);
        p4 = (short)getInt(b2, 2);
        //int t1 = getUInt(b2, 2);
        buf.get(b2, 0, 2);
        p5 = (short)getInt(b2, 2);
        //t1 = getUInt(b2, 2);
        buf.get(b2, 0, 2);
        p6 = (short)getInt(b2, 2);
        //t1 = getUInt(b2, 2);
        buf.get(b2, 0, 2);
        p7 = (short)getInt(b2, 2);
        buf.get(b2, 0, 2);
        p8 = (short)getInt(b2, 2);
        buf.get(b2, 0, 2);
        p9 = (short)getInt(b2, 2);
        buf.get(b2, 0, 2);
        p10 = (short)getUInt(b2, 2) ; //bytesToInt(b2[0], b2[1], true); //       getInt(b2, 2); //
        off += 14;

        buf.get(b2, 0, 2);
        numberOfMaps = (short)getInt(b2, 2);
        ncfile.addAttribute(null, new Attribute("NumberOfMaps",new Short(numberOfMaps)));
        off += 2;
        buf.get(b4, 0, 4);
        //tInt = (Integer)convert(b4, DataType.INT, -1);
        offsetToSymbologyBlock = getInt(b4, 4);
        //ncfile.addAttribute(null, new Attribute("offset_symbology_block",new Integer(offsetToSymbologyBlock)));
        off += 4;
        buf.get(b4, 0, 4);
        //tInt = (Integer)convert(b4, DataType.INT, -1);
        offsetToGraphicBlock = getInt(b4, 4);
        //ncfile.addAttribute(null, new Attribute("offset_graphic_block",new Integer(offsetToGraphicBlock)));
        off += 4;
        buf.get(b4, 0, 4);
        //tInt = (Integer)convert(b4, DataType.INT, -1);
        offsetToTabularBlock = getInt(b4, 4);
        //ncfile.addAttribute(null, new Attribute("offset_tabular_block",new Integer(offsetToTabularBlock)));
        off += 4;

        return  new Pinfo (divider, latitude, longitude, height, pcode, opmode, threshold,
                           sequenceNumber, volumeScanNumber, volumeScanDate, volumeScanTime,
                            productDate, productTime, p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,
                            elevationNumber, numberOfMaps, offsetToSymbologyBlock,
                            offsetToGraphicBlock, offsetToTabularBlock);

        //return pinfo;

    }

  //
  /**
   * this converts a byte array to another primitive array
   * @param barray
   * @param dataType
   * @param nelems
   * @param byteOrder
   * @return
   */
    protected Object convert( byte[] barray, DataType dataType, int nelems, int byteOrder) {

        if (dataType == DataType.BYTE) {
          return barray;
        }

        if (dataType == DataType.CHAR) {
          return IospHelper.convertByteToChar( barray);
        }

        ByteBuffer bbuff = ByteBuffer.wrap( barray);
        if (byteOrder >= 0)
          bbuff.order( byteOrder == ucar.unidata.io.RandomAccessFile.LITTLE_ENDIAN? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);

        if (dataType == DataType.SHORT) {
          ShortBuffer tbuff = bbuff.asShortBuffer();
          short[] pa = new short[nelems];
          tbuff.get( pa);
          return pa;

        } else if (dataType == DataType.INT) {
          IntBuffer tbuff = bbuff.asIntBuffer();
          int[] pa = new int[nelems];
          tbuff.get( pa);
          return pa;

        } else if (dataType == DataType.FLOAT) {
          FloatBuffer tbuff = bbuff.asFloatBuffer();
          float[] pa = new float[nelems];
          tbuff.get( pa);
          return pa;

        } else if (dataType == DataType.DOUBLE) {
          DoubleBuffer tbuff = bbuff.asDoubleBuffer();
          double[] pa = new double[nelems];
          tbuff.get( pa);
          return pa;
        }

        throw new IllegalStateException();
    }

  //
  /**
   * this converts a byte array to a wrapped primitive (Byte, Short, Integer, Double, Float, Long)
   * @param barray
   * @param dataType
   * @param byteOrder
   * @return
   */
    protected Object convert( byte[] barray, DataType dataType, int byteOrder) {

        if (dataType == DataType.BYTE) {
          return new Byte( barray[0]);
        }

        if (dataType == DataType.CHAR) {
          return new Character((char) barray[0]);
        }

        ByteBuffer bbuff = ByteBuffer.wrap( barray);
        if (byteOrder >= 0)
          bbuff.order( byteOrder == ucar.unidata.io.RandomAccessFile.LITTLE_ENDIAN? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);

        if (dataType == DataType.SHORT) {
          ShortBuffer tbuff = bbuff.asShortBuffer();
          return new Short(tbuff.get());

        } else if (dataType == DataType.INT) {
          IntBuffer tbuff = bbuff.asIntBuffer();
          return new Integer(tbuff.get());

        } else if (dataType == DataType.LONG) {
          LongBuffer tbuff = bbuff.asLongBuffer();
          return new Long(tbuff.get());

        } else if (dataType == DataType.FLOAT) {
          FloatBuffer tbuff = bbuff.asFloatBuffer();
          return new Float(tbuff.get());

        } else if (dataType == DataType.DOUBLE) {
          DoubleBuffer tbuff = bbuff.asDoubleBuffer();
          return new Double(tbuff.get());
        }

        throw new IllegalStateException();
    }


  //////////////////////////////////////////////////////////////////////////
  // utilities



    /**
    * Flush all data buffers to disk.
    * @throws IOException
    */
    public void flush() throws IOException {
        raf.flush();
    }

    /**
    *  Close the file.
    * @throws IOException
    */
    public void close() throws IOException {
        if (raf != null)
          raf.close();
    }


    /**
    * Name:       IsZlibed
    *
    * Purpose:    Check a two-byte sequence to see if it indicates the start of
    *             a zlib-compressed buffer
    *
    */
    int isZlibHed( byte[] buf ){
        short b0 = convertunsignedByte2Short(buf[0]);
        short b1 = convertunsignedByte2Short(buf[1]);

        if ( (b0 & 0xf) == Z_DEFLATED ) {
          if ( (b0 >> 4) + 8 <= DEF_WBITS ) {
            if ( (((b0 << 8) + b1) % 31)==0 ) {
              return 1;
            }
          }
        }

        return 0;

    }

    /*
    ** Name:       IsEncrypt
    **
    ** Purpose:    Check a two-byte sequence to see if it indicates the start of
    **             an encrypted image.
    **
    */
    int IsEncrypt( byte[] buf )
    {
        /*
        ** These tests were deduced from inspection from encrypted NOAAPORT files.
        */
        String b = new String(buf);
        if ( b.startsWith("R3") ) {
        return 1;
        }

        return 0;
    }


    /*
    ** Name:    GetZlibedNexr
    **
    ** Purpose: Read bytes from a NEXRAD Level III product into a buffer
    **          This routine reads compressed image data for Level III formatted file.
    **          We referenced McIDAS GetNexrLine function
    */
    byte[] GetZlibedNexr( byte[] buf, int buflen, int hoff ) throws IOException
    {
      //byte[]  uncompr = new byte[ZLIB_BUF_LEN ]; /* decompression buffer          */
      //long    uncomprLen = ZLIB_BUF_LEN;        /* length of decompress space    */
      int             doff ;                   /* # bytes offset to image       */
      int             numin;                /* # input bytes processed       */



      numin = buflen - hoff ;

      if( numin <= 0 )
      {
        log.warn(" No compressed data to inflate "+raf.getLocation());
        return null;
      }
      //byte[]  compr = new byte[numin-4];  /* compressed portion */
      /*
      ** Uncompress first portion of the image.  This should include:
      **
      **     SHO\r\r\n             <--+
      **     SEQ#\r\r\n               |  hoff bytes long
      **     WMO header\r\r\n         |
      **     PIL\r\r\n             <--+
      **
      **  -> CCB
      **     WMO header
      **     PIL
      **     portion of the image
      **
      */
      /* a new copy of buff with only compressed bytes */

      System.arraycopy( buf, hoff, buf, hoff, numin - 4);

      // decompress the bytes
      int resultLength;
      int result = 0;
      // byte[] inflateData = null;
      byte[] tmp;
      int  uncompLen = 24500;        /* length of decompress space    */
      byte[] uncomp = new byte[uncompLen];
      Inflater inflater = new Inflater( false);

      inflater.setInput(buf, hoff, numin-4);
      int offset = 0;
      int limit = 20000;

      while ( inflater.getRemaining() > 0 )
      {
          try {
            resultLength = inflater.inflate(uncomp, offset, 4000);
          }
          catch (DataFormatException ex) {
            System.out.println("ERROR on inflation "+ex.getMessage());
            ex.printStackTrace();
            throw new IOException( ex.getMessage());
          }
          offset = offset + resultLength;
          result = result + resultLength;
          if( result > limit ) {
              // when uncomp data larger then limit, the uncomp need to increase size
              tmp = new byte[ result];
              System.arraycopy(uncomp, 0, tmp, 0, result);
              uncompLen = uncompLen + 10000;
              uncomp = new byte[uncompLen];
              System.arraycopy(tmp, 0, uncomp, 0, result);
          }
          if( resultLength == 0 ) {
               int tt = inflater.getRemaining();
               byte [] b2 = new byte[2];
               System.arraycopy(buf,hoff+numin-4-tt, b2, 0, 2);
               if(result+tt > uncompLen){
                      tmp = new byte[ result];
                      System.arraycopy(uncomp, 0, tmp, 0, result);
                      uncompLen = uncompLen + 10000;
                      uncomp = new byte[uncompLen];
                      System.arraycopy(tmp, 0, uncomp, 0, result);
               }
               if( isZlibHed( b2 ) == 0 ) {
                  System.arraycopy(buf, hoff+numin-4-tt, uncomp, result, tt);
                  result = result + tt;
                  break;
               }
               inflater.reset();
               inflater.setInput(buf, hoff+numin-4-tt, tt);
          }

      }

      inflater.end();
      /*
      ** Find out how long CCB is.  This is done by using the lower order
      ** 6 bits from the first uncompressed byte and all 8 bits of the
      ** second uncompressed byte.
      */
      byte   b1, b2;
      b1 = uncomp[0];
      b2 = uncomp[1];
      doff  = 2 * (((b1 & 63) << 8) + b2);

      for ( int i = 0; i < 2; i++ ) {                         /* eat WMO and PIL */
        while ( (doff < result ) && (uncomp[doff] != '\n') ) doff++;
        doff++;
      }

      byte[] data = new byte[ result - doff];

      System.arraycopy(uncomp, doff, data, 0, result - doff);

      //
      /*
      ** Copy header bytes to decompression buffer.  The objective is to
      ** create an output buffer that looks like an uncompressed NOAAPORT
      ** NEXRAD product:
      **
      **   Section               Product               Example             End
      **            +--------------------------------+
      **            |                                |
      **      1     |        start of product        | CTRL-A              \r\r\n
      **            |                                |
      **            +--------------------------------+
      **            |                                |
      **      2     |        sequence number         | 237                 \r\r\n
      **            |                                |
      **            +--------------------------------+
      **            |                                |
      **      3     |          WMO header            | SDUS53 KARX 062213  \r\r\n
      **            |                                |
      **            +--------------------------------+
      **            |                                |
      **      4     |             PIL                | N0RARX              \r\r\n
      **            |                                |
      **            +--------------------------------+
      **            |                                |
      **      5     |                                | AAO130006R2 CH-1
      **            |                                | Interface Control
      **            |             CCB                | Document (ICD)
      **            |                                | for the NWS NWSTG
      **            |                                | Figure 7-1 p 38
      **            |                                |
      **            +--------------------------------+
      **            |                                |
      **      6     |          WMO header            | SDUS53 KARX 062213  \r\r\n
      **            |                                |
      **            +--------------------------------+
      **            |                                |
      **      7     |             PIL                | N0RARX              \r\r\n
      **            |                                |
      **            +--------------------------------+
      **            |                                |
      **            |                                |
      **            |                                |
      **            |                                |
      **      8     |            image               |
      **            |                                |
      **            |                                |
      **            |                                |
      **            |                                |
      **            +--------------------------------+
      **            |                                |
      **      9     |            trailer             | \r\r\nETX
      **            |                                |
      **            +--------------------------------+
      **            |                                |
      **     10     |     Unidata floater trailer    | \0\0
      **            |                                |
      **            +--------------------------------+
      **
      ** Sections 5-8 are zlib compressed.  They must be uncompressed and
      ** read to find out where the image begins.  When this is done, sections
      ** 5-7 are thrown away and 8 is returned immediately following 4.
      ** Section 9 and, if it is there, section 10 are also thrown away.
      **
      */

      return data;

    }




    /*
    ** Name:       code_lookup
    **
    ** Purpose:    Derive some derivable metadata
    **
    */
    static int code_typelookup( int code )
    {
      int type;
      final int[] types = {
        Other, Other, Other, Other, Other,                          /*   0-  9 */
        Other, Other, Other, Other, Other,
        Other, Other, Other, Other, Other,                          /*  10- 19 */
        Other, Base_Reflect, Base_Reflect, Base_Reflect, Base_Reflect,
        BaseReflect248, Base_Reflect, Velocity,                     /*  20- 29 */
        Velocity, Velocity, Velocity, Velocity, Velocity, SPECTRUM, SPECTRUM,
        SPECTRUM, Other, DigitalHybridReflect, Other, Other,        /*  30- 39 */
        Comp_Reflect, Comp_Reflect, Comp_Reflect, Comp_Reflect, Other,
        Other, Echo_Tops, Other, Other, Other,                      /*  40- 49 */
        Other, Other, Other, VAD, Other,
        Other, Other, Other, Other, Other,                          /*  50- 59 */
        StrmRelMeanVel, StrmRelMeanVel, Vert_Liquid, Other, Other,
        Other, Other, Other, Layer_Reflect_Avg,                     /*  60- 69 */
        Layer_Reflect_Avg, Layer_Reflect_Max,
        Layer_Reflect_Max, Other, Other, Other,
        Other, Other, Other, Other, Other,                          /*  70- 79 */
        Other, Other, Other, Precip_1, Precip_3,
        Precip_Accum, Precip_Array, Other,                          /*  80- 89 */
        Other, Other, Other, Other, Other, Other, Layer_Reflect_Avg,
        Layer_Reflect_Max, Other, Other, Other,                     /*  90- 99 */
        BaseReflectivityDR, Other, Other, Other, Other, BaseVelocityDV,
        Other, Other, Other, Other, Other,                          /* 100-109 */
        Other, Other, Other, Other, Other,
        Other, Other, Other, Other, Other,                          /* 110-119 */
        Other, Other, Other, Other, Other,
        Other, Other, Other, Other, Other,                          /* 120-129 */
        Other, Other, Other, Other, Other,
        Other, Other, Other, Other, DigitalVert_Liquid,             /* 130-139 */
        EnhancedEcho_Tops, Other, Other, DigitalStormTotalPrecip, Other,
        Other, Other, Other, Other, Other,                          /* 140-149 */
        Other, Other, Other, Other, Other,
        Other, Other, Other, Other, Other,                          /* 150-159 */
        Other, Other, Other, Other, Other,
        Other, Other, Other, Other, Other,                          /* 160-169 */
        Other, Other, Other, Other, Other,
        Other, Other, Other, Other, Other,                          /* 170-179 */
        Other, Other, Other, Other, Other,
        Reflect1, Reflect1, Velocity1, Velocity1, Other,       /* 180-189 */
        SPECTRUM1, Reflect1, Reflect1, Other, Other,
      };


      if ( code < 0 || code > 189 )
        type     = Other;
      else
        type     = types[code];

      return type;

    }

    /*
     * product id table
     * @param code
     * @param elevation
     * @return
     */
    static String pname_lookup( int code, int elevation )
    {
      String pname = null;
      switch( code ){
          case 19:
              pname = "N" + elevation + "R";

            break;
          case 20:
              pname = "N0Z";
            break;
          case 25:
              pname = "N0W";
            break;
          case 27:
              pname = "N" + elevation + "V";

            break;
          case 28:
            pname = "NSP";
            break;
          case 30:
            pname = "NSW";
            break;
          case 36:
            pname = "NCO";
            break;
          case 37:
            pname = "NCR";
            break;
          case 38:
            pname = "NCZ";
            break;
          case 41:
            pname = "NET";
            break;
          case 48:
            pname = "NVW";
          case 56:
              pname = "N" + elevation + "S";
          
            break;
          case 57:
            pname = "NVL";
            break;
          case 65:
            pname = "NLL";
            break;
          case 66:
            pname = "NML";
            break;
          case 78:
            pname = "N1P";
            break;
          case 79:
            pname = "N3P";
            break;
          case 80:
            pname = "NTP";
            break;
          case 81:
            pname = "DPA";
            break;
          case 90:
            pname = "NHL";
            break;
          case 94:
            if(elevation == 1)
                pname = "NAQ";
            else if(elevation == 3)
                pname = "NBQ";
            else
                pname = "N" + elevation/2 + "Q";
            break;
          case 99:
            if(elevation == 1)
                pname = "NAU";
            else if(elevation == 3)
                pname = "NBU";
            else
                pname = "N" + elevation/2 + "U";
            break;
          case 134:
            pname = "DVL";
            break;
          case 135:
            pname = "EET";
            break;
          case 182:
            pname = "DV";
            break;
          case 187:
          case 181:
            pname = "R";
            break;
          case 186:
          case 180:
            pname = "DR";
            break;
          case 183:
            pname = "V";
            break;
          case 185:
            pname = "SW";
            break;

          default:
              break;

      }

      return pname;

    }

    /*
     * product resolution
     * @param code
     * @return
     */
    static double code_reslookup( int code )
    {

      double data_res;

      final  double[] res = {
        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    /*   0-  9 */
        0,    0,    0,    0,    0,    0,    1,    2,    4,    1,    /*  10- 19 */
        2,    4, 0.25,  0.5,    1, 0.25,  0.5,    1, 0.25,    0,    /*  20- 29 */
        1,    0,    1,    0,    0,    1,    4,    1,    4,    0,    /*  30- 39 */
        0,    4,    0,    0,    0,    0,    0,    0,    0,    0,    /*  40- 49 */
        0,    0,    0,    0,    0,  0.5,    1,    4,    0,    0,    /*  50- 59 */
        0,    0,    0,    4,    4,    4,    4,    0,    0,    0,    /*  60- 69 */
        0,    0,    0,    0,    0,    0,    0,    0,    1,    1,    /*  70- 79 */
        1,    4,    0,    0,    0,    0,    0,    0,    0,    4,    /*  80- 89 */
        4,    0,    0,    0,    1,    0,    0,    0,    0, 0.25,    /*  90- 99 */
        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    /* 100-109 */
        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    /* 110-119 */
        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    /* 120-129 */
        0,    0,    0,    0,    1,    1,    0,    0,    1,    0,    /* 130-139 */
        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    /* 140-149 */
        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    /* 150-159 */
        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    /* 160-169 */
        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    /* 170-179 */
        0,  150.0, 150.0, 0,    0,    0, 300.0,   0,    0,    0,    /* 180-189 */
      };


      if ( code < 0 || code > 189 )
        data_res = 0;
      else
        data_res = res[code];

      return data_res;

    }

    /*
     * product level tabel
     * @param code
     * @return
     */
    static int code_levelslookup( int code )
    {

      int level;

      final int[] levels = {
        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    /*   0-  9 */
        0,    0,    0,    0,    0,    0,    8,    8,    8,   16,    /*  10- 19 */
       16,   16,    8,    8,    8,   16,   16,   16,    8,    0,    /*  20- 29 */
        8,    0,  256,    0,    0,    8,    8,   16,   16,    0,    /*  30- 39 */
        0,   16,    0,    0,    0,    0,    0,    0,    0,    0,    /*  40- 49 */
        0,    0,    0,    0,    0,   16,   16,   16,    0,    0,    /*  50- 59 */
        0,    0,    0,    8,    8,    8,    8,    0,    0,    0,    /*  60- 69 */
        0,    0,    0,    0,    0,    0,    0,    0,   16,   16,    /*  70- 79 */
       16,  256,    0,    0,    0,    0,    0,    0,    0,    8,    /*  80- 89 */
        8,    0,    0,    0,  256,    0,    0,    0,    0,  256,    /*  90- 99 */
        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    /* 100-109 */
        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    /* 110-119 */
        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    /* 120-129 */
        0,    0,    0,    0,  256,  199,    0,    0,  256,    0,    /* 130-139 */
        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    /* 140-149 */
        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    /* 150-159 */
        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    /* 160-169 */
        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    /* 170-179 */
        0,   16,  256,    0,    0,    0,  256,    0,    0,    0,    /* 180-189 */
      };


      if ( code < 0 || code > 189 )
        level = 0;
      else
        level = levels[code];

      return level;

    }

    // Symbology block info for reading/writing
    class Sinfo {
      short divider;
      short id;
      int blockLength;
      short nlayers;

      Sinfo( short divider, short id, int length, short layers) {
        this.divider = divider;
        this.id = id;
        this.blockLength = length;
        this.nlayers = layers;
      }
    }

  // variable info for reading/writing
    class Vinfo {
        int xt;
        int x0;
        int yt;
        int y0;
        boolean isRadial; // is it a radial variable?
        long hoff;    // header offset
        long doff;
        boolean isZlibed;
        int[] pos;
        int[] len;
        int code;
        int level;

        Vinfo( int xt, int x0, int yt, int y0,long hoff, long doff, boolean isRadial, boolean isZ,
               int[] pos, int[] len, int code, int level ) {
            this.xt = xt;
            this.yt = yt;
            this.x0 = x0;
            this.y0 = y0;
            this.hoff = hoff;
            this.doff = doff;
            this.isRadial = isRadial;
            this.isZlibed = isZ;
            this.pos = pos;
            this.len = len;
            this.code = code;
            this.level = level;
        }
    }


  // product info for reading/writing
    class Pinfo {
        short divider, pcode, opmode, sequenceNumber, volumeScanNumber, volumeScanDate, productDate;
        double latitude, longitude;
        double height; // meters
        int volumeScanTime,  productTime;
        short p1, p2, p3, p4, p5, p6, p7, p8, p9, p10;
        short elevationNumber, numberOfMaps;
        int offsetToSymbologyBlock, offsetToGraphicBlock, offsetToTabularBlock;
        short [] threshold;
        Pinfo() {
            // do nothing ;
        }
        Pinfo (short divider , double latitude, double longitude, double height, short pcode, short opmode, short[] threshold,
               short sequenceNumber, short volumeScanNumber, short volumeScanDate, int volumeScanTime,
               short productDate, int productTime, short p1,short p2,short p3,short p4,short p5,
               short p6,short p7,short p8, short p9,short p10,
               short elevationNumber, short numberOfMaps, int offsetToSymbologyBlock,
               int offsetToGraphicBlock, int offsetToTabularBlock)   {
          this.divider = divider;
          this.latitude= latitude;
          this.longitude = longitude;
          this.height = height;
          this.pcode = pcode;
          this.opmode = opmode;
          this.sequenceNumber = sequenceNumber ;
          this.volumeScanNumber = volumeScanNumber ;
          this.volumeScanDate = volumeScanDate ;
          this.volumeScanTime = volumeScanTime ;
          this.productDate = productDate ;
          this.productTime = productTime ;
          this.p1 = p1 ;
          this.p2 = p2 ;
          this.p3 = p3 ;
          this.p4 = p4;
          this.p5 = p5 ;
          this.p6 = p6 ;
          this.p7 = p7 ;
          this.p8 = p8 ;
          this.p9 = p9 ;
          this.p10 = p10 ;
          this.threshold = threshold;
          this.elevationNumber = elevationNumber ;
          this.numberOfMaps = numberOfMaps ;
          this.offsetToSymbologyBlock = offsetToSymbologyBlock ;
          this.offsetToGraphicBlock = offsetToGraphicBlock ;
          this.offsetToTabularBlock = offsetToTabularBlock ;

        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy