cdm/src/main/java/ucar/nc2/iosp/nids/Nidsheader.java
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 ;
        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, CDM.utf8Charset);
            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];

            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, CDM.utf8Charset);
                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());
                uncompdata = new byte[b.length - hoff];
                System.arraycopy(b, hoff, uncompdata, 0, b.length - hoff);
              }
        }
        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 );

    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<sinfo.nlayers ; i++ ){
          hedsiz = klayer;
          bos.position(hedsiz);
          short Divlen_divider = bos.getShort();
          hedsiz += 2;
          int Divlen_length = bos.getInt();
          hedsiz += 4;

          if ( Divlen_divider != -1 ) {
            log.warn( "error reading length divider "+raf.getLocation());
          }

          int icount = 0;
          int plen;

          while (icount < Divlen_length ) {
              int boff = klayer + icount + 6;
              bos.position(boff);
              bos.get(b2);
              int pkcode = getUInt(b2, 2);
              hedsiz += 2;
              boff += 2;
              switch(pkcode)
              {
                 case 18:  //  DPA
                 case 17: //   (pkcode == 0x11)   Digital Precipitation Array
                      hedsiz += 8;
                      plen = pcode_DPA( bos, boff, hoff, hedsiz, isZ, i, pkcode);
                      break;
                 case 10:    //     (pkcode == 0xA)
                      if(pkcode10Doff == null)  {
                          pkcode10Doff = new int[250];
                          pkcode10Dlen = new int[250];
                      }
                      plen =  bos.getShort();   // for unlinked Vector Packet the length of data block
                      pkcode10Doff[pcode10Number] = boff + 2;
                      pkcode10Dlen[pcode10Number] = ( plen - 2 ) / 8;
                      pcode10Number++;
                      //pcode_10n7( bos, boff, hoff, isZ, pkcode );
                      break;
                 case 1:
                      if(pkcode1Doff == null) {
                          pkcode1Doff = new int[250];
                          pkcode1Size = new int[250];
                      }
                      plen = bos.getShort();
                      pkcode1Doff[pcode1Number] = boff + 2;
                      pkcode1Size[pcode1Number] = plen - 4;
                      pcode1Number++;
                      break;
                 case 2:
                      if(pkcode2Doff == null) {
                          pkcode2Doff = new int[250];
                          pkcode2Size = new int[250];
                      }
                      plen = bos.getShort();
                      pkcode2Doff[pcode2Number] = boff + 2;
                      pkcode2Size[pcode2Number] = plen - 4;
                      pcode2Number++;
                      break;
                 case 8:       //text string
                      if(pkcode8Doff == null) {
                          pkcode8Doff = new int[550];
                          pkcode8Size = new int[550];
                      }
                      plen = bos.getShort();
                      pkcode8Doff[pcode8Number] = boff + 2;
                      pkcode8Size[pcode8Number] = plen - 6;
                      pcode8Number++;
                      break;
                 case 3:
                 case 11:
                 case 25:
                      if(pkcode25Doff == null) {
                          pkcode25Doff = new int[250];
                      }
                      plen = bos.getShort();
                      pkcode25Doff[pcode25Number] = boff + 2;
                      pcode25Number++;
                      break;
                 case 12:
                      if(pkcode12Doff == null) {
                          pkcode12Doff = new int[250];
                          pkcode12Dlen = new int[250];
                      }
                      plen = bos.getShort();
                      pkcode12Doff[pcode12Number] = boff + 2;
                      pkcode12Dlen[pcode12Number] = plen/4;
                      pcode12Number++;
                      break;
                 case 13:
                      if(pkcode13Doff == null) {
                          pkcode13Doff = new int[250];
                          pkcode13Dlen = new int[250];
                      }
                      plen = bos.getShort();
                      pkcode13Doff[pcode13Number] = boff + 2;
                      pkcode13Dlen[pcode13Number] = plen/4;
                      pcode13Number++;
                      break;
                 case 14:
                      if(pkcode14Doff == null) {
                          pkcode14Doff = new int[250];
                          pkcode14Dlen = new int[250];
                      }
                      plen = bos.getShort();
                      pkcode14Doff[pcode14Number] = boff + 2;
                      pkcode14Dlen[pcode14Number] = plen/4;
                      pcode14Number++;
                      break;
                 case 15:
                      if(pkcode15Doff == null) {
                          pkcode15Doff = new int[250];
                          pkcode15Dlen = new int[250];
                      }
                      plen = bos.getShort();
                      pkcode15Doff[pcode15Number] = boff + 2;
                      pkcode15Dlen[pcode15Number] = plen/6;
                      pcode15Number++;
                      break;
                 case 166:
                      if(pkcode16Doff == null) {
                          pkcode16Doff = new int[250];
                          pkcode16Dlen = new int[250];
                      }
                      plen = bos.getShort();
                      pkcode16Doff[pcode16Number] = boff + 2;
                      pkcode16Dlen[pcode16Number] = plen/4;
                      pcode16Number++;
                      break;
                  case 19:
                      if(pkcode19Doff == null) {
                          pkcode19Doff = new int[250];
                          pkcode19Dlen = new int[250];
                      }
                      plen = bos.getShort();
                      pkcode19Doff[pcode19Number] = boff + 2;
                      pkcode19Dlen[pcode19Number] = plen/10;
                      pcode19Number++;
                      break;
                  case 20:
                      if(pkcode20Doff == null) {
                          pkcode20Doff = new int[250];
                          pkcode20Dlen = new int[250];
                      }
                      plen = bos.getShort();
                      pkcode20Doff[pcode20Number] = boff + 2;
                      pkcode20Dlen[pcode20Number] = plen/8;
                      pcode20Number++;
                      break;
                 case 4:    // wind barb
                      if(pkcode4Doff == null) {
                          pkcode4Doff = new int[1000];
                      }
                      plen = bos.getShort();
                      pkcode4Doff[pcode4Number] = boff + 2;
                      pcode4Number++;
                      break;
                 case 5:  //   Vector Arrow Data
                      if(pkcode5Doff == null) {
                          pkcode5Doff = new int[1000];
                      }
                      plen = bos.getShort();
                      pkcode5Doff[pcode5Number] = boff + 2;
                      pcode5Number++;
                      break;
                 case 43:
                      plen = bos.getShort();
                      break;
                 case 23:
                 case 24:
                      plen = bos.getShort();
                      int poff = 2;
                      while (poff < plen){
                          int pcode = bos.getShort();
                          int len = bos.getShort();
                          switch (pcode)
                          {
                             case 2:
                                 if(pkcode2Doff == null) {
                                     pkcode2Doff = new int[250];
                                     pkcode2Size = new int[250];
                                 }
                                 pkcode2Doff[pcode2Number] = boff + poff + 4;
                                 pkcode2Size[pcode2Number] = len - 4;
                                 pcode2Number++;
                                 break;
                             case 6:
                                 if(pkcode6Doff == null) {
                                     pkcode6Doff = new int[250];
                                     pkcode6Dlen = new int[250];
                                 }
                                 pkcode6Doff[pcode6Number] = boff + poff + 4;
                                 pkcode6Dlen[pcode6Number] = (len - 6)/4;
                                 pcode6Number++;
                                 break;
                             case 25:
                                 if(pkcode25Doff == null) {
                                     pkcode25Doff = new int[250];
                                 }
                                 pkcode25Doff[pcode25Number] = boff + poff + 4;
                                 pcode25Number++;
                                 break;
                             default:
                                log.error( "error reading pcode= " + pcode+" "+raf.getLocation());
                                throw new IOException("error reading pcode, " +
                                        "unable to handle the packet with code "
                                        + pcode);
                          }
                          poff = poff + len + 4;
                          // Need to advance the file's position
                          bos.position(bos.position() + len);
                      }
                      break;
                  case 0x0802:
                      log.warn("Encountered unhandled packet code 0x0802 (contour color) -- reading past.");
                      Divlen_divider = bos.getShort(); // Color marker
                      if (Divlen_divider != 0x0002) {
                          log.warn("Missing color marker!");
                      }
                      plen = 2;
                      break;
                  case 0x0E03:
                      log.warn("Encountered unhandled packet code 0x0E03 (linked contours) -- reading past.");
                      Divlen_divider = bos.getShort(); // Start marker
                      if (Divlen_divider != 0x8000) {
                          log.warn("Missing start marker!");
                      }
                      // Read past start x, y for now
                      bos.getShort();
                      bos.getShort();
                      plen = 6 + bos.getShort();
                      break;

                 default:
                      if ( pkcode == 0xAF1F  || pkcode == 16) {              /* radial image                  */
                          hedsiz += pcode_radial( bos, hoff, hedsiz, isZ, uncompdata, pinfo.threshold) ;
                          //myInfo = new Vinfo (cname, numX, numX0, numY, numY0, hoff, hedsiz, isR, isZ);
                          plen = Divlen_length;
                          break;
                      }
                      else if ( pkcode == 28) {              /* radial image                  */
                          hedsiz += pcode_generic( bos, hoff, hedsiz, isZ, uncompdata, pinfo.threshold) ;
                          //myInfo = new Vinfo (cname, numX, numX0, numY, numY0, hoff, hedsiz, isR, isZ);
                          plen = Divlen_length;
                          break;
                      }
                      else if (pkcode == 0xBA0F ||pkcode == 0xBA07 )
                      {      /* raster image                  */
                          hedsiz += pcode_raster( bos, (short)pkcode, hoff, hedsiz, isZ, uncompdata);
                          //myInfo = new Vinfo (cname, numX, numX0, numY, numY0, hoff, hedsiz, isR, isZ);
                          plen = Divlen_length;
                          break;
                      }
                      else
                      {
                          log.error( "error reading pkcode equals " + pkcode+" "+raf.getLocation());
                          throw new IOException("error reading pkcode, unable to handle the product with code " + pkcode);
                      }

                  // size and beginning data position in file

              } //end of switch
              icount = icount + plen + 4;
          }

          klayer = klayer + Divlen_length + 6;
     }

      //int curDoff = hedsiz;

      if(pkcode8Doff != null){
          pcode_128( pkcode8Doff, pkcode8Size, 8, hoff, pcode8Number, "textStruct_code8", "",isZ);
      }
      if (pkcode1Doff != null){
          pcode_128( pkcode1Doff, pkcode1Size, 1, hoff, pcode1Number, "textStruct_code1", "", isZ);
      }
      if (pkcode2Doff != null){
          pcode_128( pkcode2Doff, pkcode2Size, 2, hoff, pcode2Number, "textStruct_code2", "", isZ);
      }
      if (pkcode10Doff != null){
          pcode_10n9( pkcode10Doff, pkcode10Dlen, hoff, pcode10Number, isZ);
      }
      if (pkcode4Doff != null){
          pcode_4( pkcode4Doff, hoff, pcode4Number, isZ);
      }
      if (pkcode5Doff != null){
          pcode_5( pkcode5Doff, hoff, pcode5Number, isZ);
      }
      if (pkcode6Doff != null){
          pcode_6n7( pkcode6Doff, pkcode6Dlen, hoff, pcode6Number, isZ, "linkedVector", 6);
      }
      if (pkcode25Doff != null){
          pcode_25( pkcode25Doff, hoff, pcode25Number, isZ);
      }
      if (pkcode12Doff != null){
          pcode_12n13n14( pkcode12Doff, pkcode12Dlen, hoff, pcode12Number, isZ, "TVS", 12);
      }
      if (pkcode13Doff != null){
          pcode_12n13n14( pkcode13Doff, pkcode13Dlen, hoff, pcode13Number, isZ, "hailPositive", 13);
      }
      if (pkcode14Doff != null){
          pcode_12n13n14( pkcode14Doff, pkcode14Dlen, hoff, pcode14Number, isZ, "hailProbable", 14);
      }
      if (pkcode19Doff != null){
          pcode_12n13n14( pkcode19Doff, pkcode19Dlen, hoff, pcode19Number, isZ, "hailIndex", 19);
      }
      if (pkcode20Doff != null){
          pcode_12n13n14( pkcode20Doff, pkcode20Dlen, hoff, pcode20Number, isZ, "mesocyclone", 20);
      }
    } else {
      log.debug ( "GetNexrDirs:: no product symbology block found (no image data) " +raf.getLocation());

    }

    if ( pinfo.offsetToTabularBlock != 0 ) {
         int tlayer = pinfo.offsetToTabularBlock*2;
         bos.position(tlayer);
         if( bos.hasRemaining()) {

             short tab_divider = bos.getShort();
             if ( tab_divider != -1) {
                 log.error ( "Block divider not found "+raf.getLocation());
                 throw new IOException("error reading graphic alphanumeric block" );
             }
             short tab_bid = bos.getShort();
             int tblen = bos.getInt();

             bos.position(tlayer+116);
             int inc = bos.getInt();
             bos.position(tlayer+128); // skip the second header and prod description

             tab_divider = bos.getShort();
             if ( tab_divider != -1) {
                 log.error ( "tab divider not found "+raf.getLocation());
                 throw new IOException("error reading graphic alphanumeric block" );
             }
             int npage = bos.getShort();

             int ppos =  bos.position();

             ArrayList dims =  new ArrayList();
             Dimension tbDim = new Dimension("pageNumber", npage);
             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(CDM.LONG_NAME, "Graphic Product Message"));
             ncfile.addVariable(null, ppage);
             ppage.setSPobject( new Vinfo (npage, 0, tblen, 0, hoff, ppos, isR, isZ, null, null, tab_bid, 0));
         }

     }

     if ( pinfo.offsetToGraphicBlock != 0 ) {
         int gpkcode1Doff[] = null;
         int gpkcode2Doff[] = null;
         int gpkcode10Doff[] = null;
         int gpkcode10Dlen[] = null;
         int gpkcode8Doff[] = null;
         int gpkcode1Size[] = null;
         int gpkcode2Size[] = null;
         int gpkcode8Size[] = null;
         int gpcode1Number = 0;
         int gpcode10Number = 0;
         int gpcode8Number = 0;
         int gpcode2Number = 0;
         int tlayer = pinfo.offsetToGraphicBlock*2;
         bos.position(tlayer);
         short graphic_divider = bos.getShort();
         short graphic_bid = bos.getShort();
         if(graphic_divider!=-1 || graphic_bid != 2) {
               log.error( "error reading graphic alphanumeric block "+raf.getLocation());
               throw new IOException("error reading graphic alphanumeric block" );
         }
         int blen = bos.getInt();
         int clen = 0;
         int npage = bos.getShort();
         int lpage ;
         int ipage = 0;
         int plen ;

         while ( (clen < blen) && (ipage < npage) ) {
          //  bos.position(ppos);
            int ppos = bos.position();
            ipage =  bos.getShort();
            lpage =  bos.getShort();
            int icnt = 0;
            ppos = ppos + 4;
            while (icnt < lpage)
            {
                bos.position(ppos+icnt);
                int pkcode = bos.getShort();
                if(pkcode == 8 ) {
                   if(gpkcode8Doff == null) {
                          gpkcode8Doff = new int[550];
                          gpkcode8Size = new int[550];
                   }
                   plen = bos.getShort();
                   gpkcode8Doff[gpcode8Number] = ppos + 4 + icnt;
                   gpkcode8Size[gpcode8Number] = plen - 6;
                   icnt += plen + 4;
                   gpcode8Number++;
                }
                else if ( pkcode == 1 ) {
                   if(gpkcode1Doff == null) {
                          gpkcode1Doff = new int[550];
                          gpkcode1Size = new int[550];
                   }
                   plen = bos.getShort();
                   gpkcode1Doff[gpcode1Number] = ppos + 4 + icnt;
                   gpkcode1Size[gpcode1Number] = plen - 4;
                   icnt += plen + 4;
                   gpcode1Number++;
                }
                else if ( pkcode == 10 ) {
                   if(gpkcode10Doff == null)  {
                          gpkcode10Doff = new int[250];
                          gpkcode10Dlen = new int[250];
                   }
                   plen =  bos.getShort();   // for unlinked Vector Packet the length of data block

                   gpkcode10Doff[gpcode10Number] = ppos + 4+ icnt;
                   gpkcode10Dlen[gpcode10Number] = ( plen - 2 ) / 8;
                   icnt += plen + 4;
                   gpcode10Number++;
                }  else {
                   plen = bos.getShort();
                   icnt += plen + 4;
                }

              //  else {
              //      out.println( "error reading pkcode equals " + pkcode);
              //      throw new IOException("error reading pkcode in graphic alpha num block " + pkcode);
              //  }

            }
            ppos = ppos + lpage + 4;
            clen = clen + lpage + 4;
         }

         if(gpkcode8Doff != null){
             pcode_128( gpkcode8Doff, gpkcode8Size, 8, hoff, gpcode8Number, "textStruct_code8g", "g", isZ);
         }
         if(gpkcode2Doff != null){
             pcode_128( gpkcode2Doff, gpkcode2Size, 2, hoff, gpcode8Number, "textStruct_code2g", "g", isZ);
         }
         if(gpkcode1Doff != null){
             pcode_128( gpkcode1Doff, gpkcode1Size, 1, hoff, gpcode1Number, "textStruct_code1g", "g", isZ);
         }
         if (gpkcode10Doff != null){
             pcode_10n9( gpkcode10Doff, gpkcode10Dlen, hoff, gpcode10Number, isZ);
         }
         /*
         int ppos = bos.position();
         ArrayList dims =  new ArrayList();
         Dimension tbDim = new Dimension("pageNumber", npage, true);
         ncfile.addDimension( null, tbDim);
         dims.add( tbDim);
         Variable ppage = new Variable(ncfile, null, null, "GraphicMessagePage");
         ppage.setDimensions(dims);
         ppage.setDataType(DataType.STRING);
         ppage.addAttribute( new Attribute(CDM.LONG_NAME, "Graphic Product Message"));
         ncfile.addVariable(null, ppage);
         ppage.setSPobject( new Vinfo (npage, 0, tblen, 0, hoff, ppos, isR, isZ, null, null, graphic_bid));
           */
     }
    // finish
    ncfile.finish();
    }
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 ;
        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, CDM.utf8Charset);
            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];

            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, CDM.utf8Charset);
                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());
                uncompdata = new byte[b.length - hoff];
                System.arraycopy(b, hoff, uncompdata, 0, b.length - hoff);
              }
        }
        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 );

    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<sinfo.nlayers ; i++ ){
          hedsiz = klayer;
          bos.position(hedsiz);
          short Divlen_divider = bos.getShort();
          hedsiz += 2;
          int Divlen_length = bos.getInt();
          hedsiz += 4;

          if ( Divlen_divider != -1 ) {
            log.warn( "error reading length divider "+raf.getLocation());
          }

          int icount = 0;
          int plen;

          while (icount < Divlen_length ) {
              int boff = klayer + icount + 6;
              bos.position(boff);
              bos.get(b2);
              int pkcode = getUInt(b2, 2);
              hedsiz += 2;
              boff += 2;
              switch(pkcode)
              {
                 case 18:  //  DPA
                 case 17: //   (pkcode == 0x11)   Digital Precipitation Array
                      hedsiz += 8;
                      plen = pcode_DPA( bos, boff, hoff, hedsiz, isZ, i, pkcode);
                      break;
                 case 10:    //     (pkcode == 0xA)
                      if(pkcode10Doff == null)  {
                          pkcode10Doff = new int[250];
                          pkcode10Dlen = new int[250];
                      }
                      plen =  bos.getShort();   // for unlinked Vector Packet the length of data block
                      pkcode10Doff[pcode10Number] = boff + 2;
                      pkcode10Dlen[pcode10Number] = ( plen - 2 ) / 8;
                      pcode10Number++;
                      //pcode_10n7( bos, boff, hoff, isZ, pkcode );
                      break;
                 case 1:
                      if(pkcode1Doff == null) {
                          pkcode1Doff = new int[250];
                          pkcode1Size = new int[250];
                      }
                      plen = bos.getShort();
                      pkcode1Doff[pcode1Number] = boff + 2;
                      pkcode1Size[pcode1Number] = plen - 4;
                      pcode1Number++;
                      break;
                 case 2:
                      if(pkcode2Doff == null) {
                          pkcode2Doff = new int[250];
                          pkcode2Size = new int[250];
                      }
                      plen = bos.getShort();
                      pkcode2Doff[pcode2Number] = boff + 2;
                      pkcode2Size[pcode2Number] = plen - 4;
                      pcode2Number++;
                      break;
                 case 8:       //text string
                      if(pkcode8Doff == null) {
                          pkcode8Doff = new int[550];
                          pkcode8Size = new int[550];
                      }
                      plen = bos.getShort();
                      pkcode8Doff[pcode8Number] = boff + 2;
                      pkcode8Size[pcode8Number] = plen - 6;
                      pcode8Number++;
                      break;
                 case 3:
                 case 11:
                 case 25:
                      if(pkcode25Doff == null) {
                          pkcode25Doff = new int[250];
                      }
                      plen = bos.getShort();
                      pkcode25Doff[pcode25Number] = boff + 2;
                      pcode25Number++;
                      break;
                 case 12:
                      if(pkcode12Doff == null) {
                          pkcode12Doff = new int[250];
                          pkcode12Dlen = new int[250];
                      }
                      plen = bos.getShort();
                      pkcode12Doff[pcode12Number] = boff + 2;
                      pkcode12Dlen[pcode12Number] = plen/4;
                      pcode12Number++;
                      break;
                 case 13:
                      if(pkcode13Doff == null) {
                          pkcode13Doff = new int[250];
                          pkcode13Dlen = new int[250];
                      }
                      plen = bos.getShort();
                      pkcode13Doff[pcode13Number] = boff + 2;
                      pkcode13Dlen[pcode13Number] = plen/4;
                      pcode13Number++;
                      break;
                 case 14:
                      if(pkcode14Doff == null) {
                          pkcode14Doff = new int[250];
                          pkcode14Dlen = new int[250];
                      }
                      plen = bos.getShort();
                      pkcode14Doff[pcode14Number] = boff + 2;
                      pkcode14Dlen[pcode14Number] = plen/4;
                      pcode14Number++;
                      break;
                 case 15:
                      if(pkcode15Doff == null) {
                          pkcode15Doff = new int[250];
                          pkcode15Dlen = new int[250];
                      }
                      plen = bos.getShort();
                      pkcode15Doff[pcode15Number] = boff + 2;
                      pkcode15Dlen[pcode15Number] = plen/6;
                      pcode15Number++;
                      break;
                 case 166:
                      if(pkcode16Doff == null) {
                          pkcode16Doff = new int[250];
                          pkcode16Dlen = new int[250];
                      }
                      plen = bos.getShort();
                      pkcode16Doff[pcode16Number] = boff + 2;
                      pkcode16Dlen[pcode16Number] = plen/4;
                      pcode16Number++;
                      break;
                  case 19:
                      if(pkcode19Doff == null) {
                          pkcode19Doff = new int[250];
                          pkcode19Dlen = new int[250];
                      }
                      plen = bos.getShort();
                      pkcode19Doff[pcode19Number] = boff + 2;
                      pkcode19Dlen[pcode19Number] = plen/10;
                      pcode19Number++;
                      break;
                  case 20:
                      if(pkcode20Doff == null) {
                          pkcode20Doff = new int[250];
                          pkcode20Dlen = new int[250];
                      }
                      plen = bos.getShort();
                      pkcode20Doff[pcode20Number] = boff + 2;
                      pkcode20Dlen[pcode20Number] = plen/8;
                      pcode20Number++;
                      break;
                 case 4:    // wind barb
                      if(pkcode4Doff == null) {
                          pkcode4Doff = new int[1000];
                      }
                      plen = bos.getShort();
                      pkcode4Doff[pcode4Number] = boff + 2;
                      pcode4Number++;
                      break;
                 case 5:  //   Vector Arrow Data
                      if(pkcode5Doff == null) {
                          pkcode5Doff = new int[1000];
                      }
                      plen = bos.getShort();
                      pkcode5Doff[pcode5Number] = boff + 2;
                      pcode5Number++;
                      break;
                 case 43:
                      plen = bos.getShort();
                      break;
                 case 23:
                 case 24:
                      plen = bos.getShort();
                      int poff = 2;
                      while (poff < plen){
                          int pcode = bos.getShort();
                          int len = bos.getShort();
                          switch (pcode)
                          {
                             case 2:
                                 if(pkcode2Doff == null) {
                                     pkcode2Doff = new int[250];
                                     pkcode2Size = new int[250];
                                 }
                                 pkcode2Doff[pcode2Number] = boff + poff + 4;
                                 pkcode2Size[pcode2Number] = len - 4;
                                 pcode2Number++;
                                 break;
                             case 6:
                                 if(pkcode6Doff == null) {
                                     pkcode6Doff = new int[250];
                                     pkcode6Dlen = new int[250];
                                 }
                                 pkcode6Doff[pcode6Number] = boff + poff + 4;
                                 pkcode6Dlen[pcode6Number] = (len - 6)/4;
                                 pcode6Number++;
                                 break;
                             case 25:
                                 if(pkcode25Doff == null) {
                                     pkcode25Doff = new int[250];
                                 }
                                 pkcode25Doff[pcode25Number] = boff + poff + 4;
                                 pcode25Number++;
                                 break;
                             default:
                                log.error( "error reading pcode= " + pcode+" "+raf.getLocation());
                                throw new IOException("error reading pcode, " +
                                        "unable to handle the packet with code "
                                        + pcode);
                          }
                          poff = poff + len + 4;
                          // Need to advance the file's position
                          bos.position(bos.position() + len);
                      }
                      break;
                  case 0x0802:
                      log.warn("Encountered unhandled packet code 0x0802 (contour color) -- reading past.");
                      Divlen_divider = bos.getShort(); // Color marker
                      if (Divlen_divider != 0x0002) {
                          log.warn("Missing color marker!");
                      }
                      plen = 2;
                      break;
                  case 0x0E03:
                      log.warn("Encountered unhandled packet code 0x0E03 (linked contours) -- reading past.");
                      Divlen_divider = bos.getShort(); // Start marker
                      if (Divlen_divider != 0x8000) {
                          log.warn("Missing start marker!");
                      }
                      // Read past start x, y for now
                      bos.getShort();
                      bos.getShort();
                      plen = 6 + bos.getShort();
                      break;

                 default:
                      if ( pkcode == 0xAF1F  || pkcode == 16) {              /* radial image                  */
                          hedsiz += pcode_radial( bos, hoff, hedsiz, isZ, uncompdata, pinfo.threshold) ;
                          //myInfo = new Vinfo (cname, numX, numX0, numY, numY0, hoff, hedsiz, isR, isZ);
                          plen = Divlen_length;
                          break;
                      }
                      else if ( pkcode == 28) {              /* radial image                  */
                          hedsiz += pcode_generic( bos, hoff, hedsiz, isZ, uncompdata, pinfo.threshold) ;
                          //myInfo = new Vinfo (cname, numX, numX0, numY, numY0, hoff, hedsiz, isR, isZ);
                          plen = Divlen_length;
                          break;
                      }
                      else if (pkcode == 0xBA0F ||pkcode == 0xBA07 )
                      {      /* raster image                  */
                          hedsiz += pcode_raster( bos, (short)pkcode, hoff, hedsiz, isZ, uncompdata);
                          //myInfo = new Vinfo (cname, numX, numX0, numY, numY0, hoff, hedsiz, isR, isZ);
                          plen = Divlen_length;
                          break;
                      }
                      else
                      {
                          log.error( "error reading pkcode equals " + pkcode+" "+raf.getLocation());
                          throw new IOException("error reading pkcode, unable to handle the product with code " + pkcode);
                      }

                  // size and beginning data position in file

              } //end of switch
              icount = icount + plen + 4;
          }

          klayer = klayer + Divlen_length + 6;
     }

      //int curDoff = hedsiz;

      if(pkcode8Doff != null){
          pcode_128( pkcode8Doff, pkcode8Size, 8, hoff, pcode8Number, "textStruct_code8", "",isZ);
      }
      if (pkcode1Doff != null){
          pcode_128( pkcode1Doff, pkcode1Size, 1, hoff, pcode1Number, "textStruct_code1", "", isZ);
      }
      if (pkcode2Doff != null){
          pcode_128( pkcode2Doff, pkcode2Size, 2, hoff, pcode2Number, "textStruct_code2", "", isZ);
      }
      if (pkcode10Doff != null){
          pcode_10n9( pkcode10Doff, pkcode10Dlen, hoff, pcode10Number, isZ);
      }
      if (pkcode4Doff != null){
          pcode_4( pkcode4Doff, hoff, pcode4Number, isZ);
      }
      if (pkcode5Doff != null){
          pcode_5( pkcode5Doff, hoff, pcode5Number, isZ);
      }
      if (pkcode6Doff != null){
          pcode_6n7( pkcode6Doff, pkcode6Dlen, hoff, pcode6Number, isZ, "linkedVector", 6);
      }
      if (pkcode25Doff != null){
          pcode_25( pkcode25Doff, hoff, pcode25Number, isZ);
      }
      if (pkcode12Doff != null){
          pcode_12n13n14( pkcode12Doff, pkcode12Dlen, hoff, pcode12Number, isZ, "TVS", 12);
      }
      if (pkcode13Doff != null){
          pcode_12n13n14( pkcode13Doff, pkcode13Dlen, hoff, pcode13Number, isZ, "hailPositive", 13);
      }
      if (pkcode14Doff != null){
          pcode_12n13n14( pkcode14Doff, pkcode14Dlen, hoff, pcode14Number, isZ, "hailProbable", 14);
      }
      if (pkcode19Doff != null){
          pcode_12n13n14( pkcode19Doff, pkcode19Dlen, hoff, pcode19Number, isZ, "hailIndex", 19);
      }
      if (pkcode20Doff != null){
          pcode_12n13n14( pkcode20Doff, pkcode20Dlen, hoff, pcode20Number, isZ, "mesocyclone", 20);
      }
    } else {
      log.debug ( "GetNexrDirs:: no product symbology block found (no image data) " +raf.getLocation());

    }

    if ( pinfo.offsetToTabularBlock != 0 ) {
         int tlayer = pinfo.offsetToTabularBlock*2;
         bos.position(tlayer);
         if( bos.hasRemaining()) {

             short tab_divider = bos.getShort();
             if ( tab_divider != -1) {
                 log.error ( "Block divider not found "+raf.getLocation());
                 throw new IOException("error reading graphic alphanumeric block" );
             }
             short tab_bid = bos.getShort();
             int tblen = bos.getInt();

             bos.position(tlayer+116);
             int inc = bos.getInt();
             bos.position(tlayer+128); // skip the second header and prod description

             tab_divider = bos.getShort();
             if ( tab_divider != -1) {
                 log.error ( "tab divider not found "+raf.getLocation());
                 throw new IOException("error reading graphic alphanumeric block" );
             }
             int npage = bos.getShort();

             int ppos =  bos.position();

             ArrayList dims =  new ArrayList();
             Dimension tbDim = new Dimension("pageNumber", npage);
             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(CDM.LONG_NAME, "Graphic Product Message"));
             ncfile.addVariable(null, ppage);
             ppage.setSPobject( new Vinfo (npage, 0, tblen, 0, hoff, ppos, isR, isZ, null, null, tab_bid, 0));
         }

     }

     if ( pinfo.offsetToGraphicBlock != 0 ) {
         int gpkcode1Doff[] = null;
         int gpkcode2Doff[] = null;
         int gpkcode10Doff[] = null;
         int gpkcode10Dlen[] = null;
         int gpkcode8Doff[] = null;
         int gpkcode1Size[] = null;
         int gpkcode2Size[] = null;
         int gpkcode8Size[] = null;
         int gpcode1Number = 0;
         int gpcode10Number = 0;
         int gpcode8Number = 0;
         int gpcode2Number = 0;
         int tlayer = pinfo.offsetToGraphicBlock*2;
         bos.position(tlayer);
         short graphic_divider = bos.getShort();
         short graphic_bid = bos.getShort();
         if(graphic_divider!=-1 || graphic_bid != 2) {
               log.error( "error reading graphic alphanumeric block "+raf.getLocation());
               throw new IOException("error reading graphic alphanumeric block" );
         }
         int blen = bos.getInt();
         int clen = 0;
         int npage = bos.getShort();
         int lpage ;
         int ipage = 0;
         int plen ;

         while ( (clen < blen) && (ipage < npage) ) {
          //  bos.position(ppos);
            int ppos = bos.position();
            ipage =  bos.getShort();
            lpage =  bos.getShort();
            int icnt = 0;
            ppos = ppos + 4;
            while (icnt < lpage)
            {
                bos.position(ppos+icnt);
                int pkcode = bos.getShort();
                if(pkcode == 8 ) {
                   if(gpkcode8Doff == null) {
                          gpkcode8Doff = new int[550];
                          gpkcode8Size = new int[550];
                   }
                   plen = bos.getShort();
                   gpkcode8Doff[gpcode8Number] = ppos + 4 + icnt;
                   gpkcode8Size[gpcode8Number] = plen - 6;
                   icnt += plen + 4;
                   gpcode8Number++;
                }
                else if ( pkcode == 1 ) {
                   if(gpkcode1Doff == null) {
                          gpkcode1Doff = new int[550];
                          gpkcode1Size = new int[550];
                   }
                   plen = bos.getShort();
                   gpkcode1Doff[gpcode1Number] = ppos + 4 + icnt;
                   gpkcode1Size[gpcode1Number] = plen - 4;
                   icnt += plen + 4;
                   gpcode1Number++;
                }
                else if ( pkcode == 10 ) {
                   if(gpkcode10Doff == null)  {
                          gpkcode10Doff = new int[250];
                          gpkcode10Dlen = new int[250];
                   }
                   plen =  bos.getShort();   // for unlinked Vector Packet the length of data block

                   gpkcode10Doff[gpcode10Number] = ppos + 4+ icnt;
                   gpkcode10Dlen[gpcode10Number] = ( plen - 2 ) / 8;
                   icnt += plen + 4;
                   gpcode10Number++;
                }  else {
                   plen = bos.getShort();
                   icnt += plen + 4;
                }

              //  else {
              //      out.println( "error reading pkcode equals " + pkcode);
              //      throw new IOException("error reading pkcode in graphic alpha num block " + pkcode);
              //  }

            }
            ppos = ppos + lpage + 4;
            clen = clen + lpage + 4;
         }

         if(gpkcode8Doff != null){
             pcode_128( gpkcode8Doff, gpkcode8Size, 8, hoff, gpcode8Number, "textStruct_code8g", "g", isZ);
         }
         if(gpkcode2Doff != null){
             pcode_128( gpkcode2Doff, gpkcode2Size, 2, hoff, gpcode8Number, "textStruct_code2g", "g", isZ);
         }
         if(gpkcode1Doff != null){
             pcode_128( gpkcode1Doff, gpkcode1Size, 1, hoff, gpcode1Number, "textStruct_code1g", "g", isZ);
         }
         if (gpkcode10Doff != null){
             pcode_10n9( gpkcode10Doff, gpkcode10Dlen, hoff, gpcode10Number, isZ);
         }
         /*
         int ppos = bos.position();
         ArrayList dims =  new ArrayList();
         Dimension tbDim = new Dimension("pageNumber", npage, true);
         ncfile.addDimension( null, tbDim);
         dims.add( tbDim);
         Variable ppage = new Variable(ncfile, null, null, "GraphicMessagePage");
         ppage.setDimensions(dims);
         ppage.setDataType(DataType.STRING);
         ppage.addAttribute( new Attribute(CDM.LONG_NAME, "Graphic Product Message"));
         ncfile.addVariable(null, ppage);
         ppage.setSPobject( new Vinfo (npage, 0, tblen, 0, hoff, ppos, isR, isZ, null, null, graphic_bid));
           */
     }
    // finish
    ncfile.finish();
    }
read and parse the header of the nids/tdwr file
@param raf       input file
@param ncfile    output file
@throws IOException