/* * Copyright 1998-2015 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.gempak; import ucar.nc2.grib.grib2.*; import ucar.nc2.iosp.grid.*; import ucar.unidata.io.RandomAccessFile; import java.io.*; import java.util.ArrayList; import java.util.List; /** * Read a GEMPAK grid file * * @author Don Murray */ public class GempakGridReader extends GempakFileReader { /** * logger */ private static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(GempakGridReader.class); /** * Grid identifier */ public static final String GRID = "GRID"; /** * Grid analysis block identifier */ public static final String ANLB = "ANLB"; /** * Grid nav block identifier */ public static final String NAVB = "NAVB"; /** * Navigation Block */ private NavigationBlock navBlock; /** * Navigation Block */ private AnalysisBlock analBlock; /** * Grid index */ private GridIndex gridIndex; /** * column headers */ private static final String[] kcolnm = { "GDT1", "GTM1", "GDT2", "GTM2", "GLV1", "GLV2", "GVCD", "GPM1", "GPM2", "GPM3" }; private final String filename; /** * Bean ctor. Need to call init if you want anything to work */ GempakGridReader(String filename) { this.filename = filename; } /** * Initialize the file, read in all the metadata (ala DM_OPEN) * * @param raf RandomAccessFile to read. * @param fullCheck if true, check entire structure * @return A GempakGridReader * @throws IOException problem reading file */ public static GempakGridReader getInstance(RandomAccessFile raf, boolean fullCheck) throws IOException { GempakGridReader ggr = new GempakGridReader(raf.getLocation()); ggr.init(raf, fullCheck); return ggr; } /** * Initialize this reader. Get the Grid specific info * * @param fullCheck check to make sure there are grids we can handle * @return true if successful * @throws IOException problem reading the data */ protected boolean init(boolean fullCheck) throws IOException { boolean ok = super.init(fullCheck); if (!ok) return false; // Modeled after GD_OFIL if (dmLabel.kftype != MFGD) { logError("not a grid file"); return false; } // find the part for GRID DMPart part = getPart("GRID"); if (part == null) { logError("No part named GRID found"); return false; } int lenhdr = part.klnhdr; if (lenhdr > LLGDHD) { logError("Grid part header too long"); return false; } // int khdrln = lenhdr - 2; // check that the column names are correct for (int i = 0; i < keys.kkcol.size(); i++) { Key colkey = keys.kkcol.get(i); if (!colkey.name.equals(kcolnm[i])) { logError("Column name " + colkey + " doesn't match " + kcolnm[i]); return false; } } if (!fullCheck) { return true; } gridIndex = new GridIndex(filename); // Make the NAV and ANAL blocks float[] headerArray = getFileHeader(NAVB); if (headerArray == null) { return false; } navBlock = new NavigationBlock(headerArray); //System.out.println("nav = " + navBlock); gridIndex.addHorizCoordSys(navBlock); headerArray = getFileHeader(ANLB); if (headerArray == null) { return false; } analBlock = new AnalysisBlock(headerArray); // Make the grid headers // TODO: move this up into GempakFileReader using DM_RHDA // and account for the flipping there. List<GempakGridRecord> tmpList = new ArrayList<>(); int[] header = new int[dmLabel.kckeys]; if ((headers == null) || (headers.colHeaders == null)) { return false; } int gridNum = 0; for (int[] fullHeader : headers.colHeaders) { gridNum++; // grid numbers are 1 based if ((fullHeader == null) || (fullHeader[0] == IMISSD)) { continue; } // TODO: have GempakGridRecord skip the first word System.arraycopy(fullHeader, 1, header, 0, header.length); GempakGridRecord gh = new GempakGridRecord(gridNum, header); gh.navBlock = navBlock; String name = gh.getParameterName(); //if (name.equals("TMPK") || // name.equals("UREL") || // name.equals("VREL") || // name.equals("PMSL")) { tmpList.add(gh); //} } // reset the file size since we've gone through all the grids. fileSize = rf.length(); // find the packing types for these grids // TODO: go back to using gridList //List gridList = gridIndex.getGridRecords(); //if ( !gridList.isEmpty()) { if (!tmpList.isEmpty()) { for (GempakGridRecord gh : tmpList) { gh.packingType = getGridPackingType(gh.gridNumber); if ((gh.packingType == MDGGRB) || (gh.packingType == MDGRB2) || (gh.packingType == MDGNON)) { gridIndex.addGridRecord(gh); } } } else { return false; } // check to see if there are any grids that we can handle if (gridIndex.getGridRecords().isEmpty()) { return false; } return true; } /** * Run the program * * @param args [0] filename (required), * [1] variable name (X for default), * [2] X to not list grids * @throws IOException problem reading the file */ public static void main(String[] args) throws IOException { if (args.length == 0) { System.out.println("need to supply a GEMPAK grid file name"); System.exit(1); } try { GempakGridParameterTable.addParameters("resources/nj22/tables/gempak/wmogrib3.tbl"); GempakGridParameterTable.addParameters("resources/nj22/tables/gempak/ncepgrib2.tbl"); } catch (Exception e) { System.out.println("unable to init param tables"); } GempakGridReader ggr = getInstance(getFile(args[0]), true); String var = "PMSL"; if ((args.length > 1) && !args[1].equalsIgnoreCase("X")) { var = args[1]; } ggr.showGridInfo(args.length != 3); GempakGridRecord gh = ggr.findGrid(var); if (gh != null) { System.out.println("\n" + var + ":"); System.out.println(gh); for (int j = 0; j < 2; j++) { System.out.println("Using DP: " + ggr.useDP); float[] data = ggr.readGrid(gh); if (data != null) { System.out.println("# of points = " + data.length); int cnt = 0; int it = 10; float min = Float.POSITIVE_INFINITY; float max = Float.NEGATIVE_INFINITY; for (int i = 0; i < data.length; i++) { if (cnt == it) { cnt = 0; } cnt++; if ((data[i] != RMISSD) && (data[i] < min)) { min = data[i]; } if ((data[i] != RMISSD) && (data[i] > max)) { max = data[i]; } } System.out.println("max/min = " + max + "/" + min); } else { System.out.println("unable to decode grid data"); } ggr.useDP = !ggr.useDP; } } } /** * Get the grid index * * @return the GridIndex */ public GridIndex getGridIndex() { return gridIndex; } /** * Get the grid count * * @return the count */ public int getGridCount() { return gridIndex.getGridCount(); } /** * Get the grid packing type * * @param gridNumber grid number * @return packing type or error number * @throws IOException problem reading file */ public int getGridPackingType(int gridNumber) throws IOException { // See DM_RDTR int irow = 1; // Always 1 for grids if ((gridNumber < 1) || (gridNumber > dmLabel.kcol)) { logWarning("bad grid number " + gridNumber); return -9; } int iprt = getPartNumber("GRID"); if (iprt == 0) { logWarning("couldn't find part: GRID"); return -10; } // gotta subtract 1 because parts are 1 but List is 0 based DMPart part = parts.get(iprt - 1); // check for valid data type if (part.ktyprt != MDGRID) { logWarning("Not a valid type: " + GempakUtil.getDataType(part.ktyprt)); return -21; } int ilenhd = part.klnhdr; int ipoint = dmLabel.kpdata + (irow - 1) * dmLabel.kcol * dmLabel.kprt + (gridNumber - 1) * dmLabel.kprt + (iprt - 1); // From DM_RPKG int istart = DM_RINT(ipoint); if (istart == 0) { return -15; } int length = DM_RINT(istart); int isword = istart + 1; if (length <= ilenhd) { logWarning("length (" + length + ") is less than header length (" + ilenhd + ")"); return -15; } else if (Math.abs(length) > 10000000) { logWarning("length is huge: " + length); return -34; } int[] header = new int[ilenhd]; DM_RINT(isword, header); // int nword = length - ilenhd; isword += ilenhd; // read the data packing type return DM_RINT(isword); } /** * Find the first grid with this name * * @param parm name of grid * @return the grid header or null */ public GempakGridRecord findGrid(String parm) { List<GridRecord> gridList = gridIndex.getGridRecords(); if (gridList == null) { return null; } for (GridRecord grid : gridList) { GempakGridRecord gh = (GempakGridRecord) grid; if (gh.param.trim().equals(parm)) { return gh; } } return null; } /** * Read the data * * @param gr grid record * @return the data array * @throws IOException problem reading file */ public float[] readGrid(GridRecord gr) throws IOException { int gridNumber = ((GempakGridRecord) gr).getGridNumber(); //int irow = 1; // Always 1 for grids //int icol = gridNumber; RData data = DM_RDTR(1, gridNumber, "GRID", gr.getDecimalScale()); float[] vals = null; if (data != null) { vals = data.data; } return vals; } /** * Unpack a packed grid * * @param isword starting word (1 based) * @param nword number of words to read * @param decimalScale decimal scale * @return array of unpacked data or null; * @throws IOException problem reading data */ public float[] DM_RPKG(int isword, int nword, int decimalScale) throws IOException { // from DM_RPKG // read the data packing type float[] data; int ipktyp = DM_RINT(isword); int iiword = isword + 1; int lendat = nword - 1; if (ipktyp == MDGNON) { // no packing data = new float[lendat]; DM_RFLT(iiword, data); return data; } int iiw; int irw; if (ipktyp == MDGDIF) { iiw = 4; irw = 3; } else if (ipktyp == MDGRB2) { iiw = 4; irw = 1; } else { iiw = 3; irw = 2; } int[] iarray = new int[iiw]; float[] rarray = new float[irw]; DM_RINT(iiword, iarray); iiword = iiword + iiw; lendat = lendat - iiw; DM_RFLT(iiword, rarray); iiword = iiword + irw; lendat = lendat - irw; if (ipktyp == MDGRB2) { data = unpackGrib2Data(iiword, lendat, iarray, rarray); return data; } int nbits = iarray[0]; int misflg = iarray[1]; boolean miss = misflg != 0; int kxky = iarray[2]; // int mword = kxky; int kx = 0; if (iiw == 4) { kx = iarray[3]; } float ref = rarray[0]; float scale = rarray[1]; float difmin = 0; if (irw == 3) { difmin = rarray[2]; } data = unpackData(iiword, lendat, ipktyp, kxky, nbits, ref, scale, miss, difmin, kx, decimalScale); return data; } /** * Read packed data * * @param iiword Starting word (FORTRAN 1 based) * @param nword Number of words * @param ipktyp Packing type * @param kxky Number of grid points * @param nbits Number of bits * @param ref Reference minimum value of grid * @param scale Scaling factor * @param miss Missing data flag * @param difmin Minimum value of differences * @param kx Number of points in x direction * @param decimalScale scale of the values for the units * @return unpacked data * @throws IOException problem reading file */ private synchronized float[] unpackData(int iiword, int nword, int ipktyp, int kxky, int nbits, float ref, float scale, boolean miss, float difmin, int kx, int decimalScale) throws IOException { if (ipktyp == MDGGRB) { if (!useDP) { return unpackGrib1Data(iiword, nword, kxky, nbits, ref, scale, miss, decimalScale); } else { if (nword * 32 < kxky * nbits) { // to account for badly written files nword++; } int[] ksgrid = new int[nword]; DM_RINT(iiword, ksgrid); return DP_UGRB(ksgrid, kxky, nbits, ref, scale, miss, decimalScale); } } else if (ipktyp == MDGNMC) { return null; } else if (ipktyp == MDGDIF) { return null; } return null; } /** * flag for using DP_UGRB or not */ public boolean useDP = true; // removed static - not thread safe jcaron 12/21/14 /** * Unpack grib data packed into ints * * @param idata int array of packed data * @param kxky number of output points * @param nbits number of bits per point * @param qmin minimum (reference) value * @param scale parameter scale * @param misflg missing flag * @param decimalScale scale of value to jive with units * @return the array of unpacked values * @throws IOException problem reading from the file */ private synchronized float[] DP_UGRB(int[] idata, int kxky, int nbits, float qmin, float scale, boolean misflg, int decimalScale) throws IOException { float scaleFactor = (decimalScale == 0) ? 1.f : (float) Math.pow(10.0, -decimalScale); // //Check for valid input. // float[] grid = new float[kxky]; if ((nbits <= 1) || (nbits > 31)) { return grid; } if (scale == 0.) { return grid; } // //Compute missing data value. // int imax = (int) (Math.pow(2, nbits) - 1); // //Retrieve data points from buffer. // int iword = 0; int ibit = 1; // 1 based bit position for (int i = 0; i < kxky; i++) { // // Get the integer from the buffer. // int jshft = nbits + ibit - 33; int idat = 0; idat = (jshft < 0) ? idata[iword] >>> Math.abs(jshft) : idata[iword] << jshft; idat = idat & imax; // // Check to see if packed integer overflows into next word. LOOK fishy bit operations // if (jshft > 0) { jshft -= 32; int idat2 = 0; idat2 = idata[iword + 1] >>> Math.abs(jshft); idat = idat | idat2; } // // Compute value of word. // if ((idat == imax) && misflg) { grid[i] = RMISSD; } else { grid[i] = (qmin + idat * scale) * scaleFactor; } // // Set location for next word. // ibit += nbits; if (ibit > 32) { ibit -= 32; iword++; } /* if (i < 25) { System.out.println("grid["+i+"]: " + grid[i]); } */ } return grid; } /** * Read packed Grib1 data using ucar.grib code * * @param iiword Starting word (FORTRAN 1 based) * @param nword number of words * @param kxky size of grid (kx*ky) * @param nbits number of bits per word * @param ref reference value * @param scale scale value * @param miss replace missing * @param decimalScale scale of the values * @return unpacked data * @throws IOException problem reading file */ private float[] unpackGrib1Data(int iiword, int nword, int kxky, int nbits, float ref, float scale, boolean miss, int decimalScale) throws IOException { //System.out.println("decimal scale = " + decimalScale); float[] values = new float[kxky]; bitPos = 0; bitBuf = 0; next = 0; ch1 = 0; ch2 = 0; ch3 = 0; ch4 = 0; rf.seek(getOffset(iiword)); int idat; // save a pow call if we can float scaleFactor = (decimalScale == 0) ? 1.f : (float) Math.pow(10.0, -decimalScale); //float scaleFactor = (float) Math.pow(10.0, -decimalScale); for (int i = 0; i < values.length; i++) { idat = bits2UInt(nbits); if (miss && (idat == IMISSD)) { values[i] = IMISSD; } else { values[i] = (ref + scale * idat) * scaleFactor; } /* if (i < 25) { System.out.println("values[" + i + "] = " + values[i]); } */ } return values; } /** * Read packed Grib2 data * * @param iiword Starting word (FORTRAN 1 based) * @param lendat Number of words * @param iarray integer packing info * @param rarray float packing info * @return unpacked data * @throws IOException problem reading file */ private float[] unpackGrib2Data(int iiword, int lendat, int[] iarray, float[] rarray) throws IOException { long start = getOffset(iiword); rf.seek(start); Grib2Record gr = makeGribRecord(rf, start); float[] data = gr.readData(rf); if (((iarray[3] >> 6) & 1) == 0) { // -y scanning - flip data = gb2_ornt(iarray[1], iarray[2], iarray[3], data); } return data; } // for GempakGridReader private Grib2Record makeGribRecord(RandomAccessFile raf, long start) throws IOException { Grib2SectionIndicator is = new Grib2SectionIndicator(start, 0, 0); // apparently not in GEMPAK file (!) Grib2SectionIdentification ids = null; Grib2SectionLocalUse lus = null; Grib2SectionGridDefinition gds = null; Grib2SectionProductDefinition pds = null; Grib2SectionDataRepresentation drs = null; Grib2SectionBitMap bms = null; Grib2SectionData dataSection = null; raf.seek(start); raf.order(RandomAccessFile.BIG_ENDIAN); int secLength = raf.readInt(); if (secLength > 0) { ids = new Grib2SectionIdentification(raf); } secLength = raf.readInt(); if (secLength > 0) { lus = new Grib2SectionLocalUse(raf); } secLength = raf.readInt(); if (secLength > 0) { gds = new Grib2SectionGridDefinition(raf); } secLength = raf.readInt(); if (secLength > 0) { pds = new Grib2SectionProductDefinition(raf); } secLength = raf.readInt(); if (secLength > 0) { drs = new Grib2SectionDataRepresentation(raf); } secLength = raf.readInt(); if (secLength > 0) { bms = new Grib2SectionBitMap(raf); } secLength = raf.readInt(); if (secLength > 0) { dataSection = new Grib2SectionData(raf); if (dataSection.getMsgLength() > secLength) // presumably corrupt throw new IllegalStateException("Illegal Grib2SectionData Message Length"); } // LOOK - not dealing with repeated records return new Grib2Record(null, is, ids, lus, gds, pds, drs, bms, dataSection, false, Grib2Index.ScanModeMissing); } /** * Print out the navigation block so it looks something like this: * <pre> * GRID NAVIGATION: * PROJECTION: LCC * ANGLES: 25.0 -95.0 25.0 * GRID SIZE: 93 65 * LL CORNER: 12.19 -133.46 * UR CORNER: 57.29 -49.38 * </pre> */ public void printNavBlock() { StringBuilder buf = new StringBuilder("GRID NAVIGATION:"); if (navBlock != null) { buf.append(navBlock.toString()); } else { buf.append("\n\tUNKNOWN GRID NAVIGATION"); } System.out.println(buf.toString()); } /** * Print out the analysis block so it looks something like this: */ public void printAnalBlock() { StringBuilder buf = new StringBuilder("GRID ANALYSIS BLOCK:"); if (analBlock != null) { buf.append(analBlock.toString()); } else { buf.append("\n\tUNKNOWN ANALYSIS TYPE"); } System.out.println(buf.toString()); } /** * Get list of grids * * @return list of grids */ public List<GridRecord> getGridList() { return gridIndex.getGridRecords(); } /** * Print out the grids. */ public void printGrids() { List<GridRecord> gridList = gridIndex.getGridRecords(); if (gridList == null) return; System.out.println(" NUM TIME1 TIME2 LEVL1 LEVL2 VCORD PARM"); for (GridRecord aGridList : gridList) { System.out.println(aGridList); } } /** * List out the grid information (aka GDINFO) * * @param printGrids print each grid record */ public void showGridInfo(boolean printGrids) { List gridList = gridIndex.getGridRecords(); System.out.println("\nGRID FILE: " + getFilename() + "\n"); printNavBlock(); System.out.println(""); printAnalBlock(); System.out.println("\nNumber of grids in file: " + gridList.size()); System.out.println("\nMaximum number of grids in file: " + dmLabel.kcol); System.out.println(""); if (printGrids) { printGrids(); } } /** * gb2_ornt * <p/> * This function checks the fields scanning mode flags and re-orders * the grid point values so that they traverse left to right for each * row starting at the bottom row. * <p/> * gb2_ornt ( kx, ky, scan_mode, ingrid, fgrid, iret ) * <p/> * Input parameters: * kx int Number of columns * ky int Number of rows * scan_mode int GRIB2 scanning mode flag * *ingrid float unpacked GRIB2 grid data * <p/> * Output parameters: * *fgrid float Unpacked grid data * *iret int Return code * -40 = scan mode not implemented * <p/> * Log: * S. Gilbert 1/04 * * @param kx number of points in X * @param ky number of points in Y * @param scan_mode scan mode * @param ingrid grid to flip * @return grid which starts at lower left */ private float[] gb2_ornt(int kx, int ky, int scan_mode, float[] ingrid) { float[] fgrid = new float[ingrid.length]; int ibeg, jbeg, iinc, jinc, itmp; int icnt, jcnt, kcnt, idxarr; int idrct, jdrct, consec, boustr; idrct = (scan_mode >> 7) & 1; jdrct = (scan_mode >> 6) & 1; consec = (scan_mode >> 5) & 1; boustr = (scan_mode >> 4) & 1; if (idrct == 0) { ibeg = 0; iinc = 1; } else { ibeg = kx - 1; iinc = -1; } if (jdrct == 1) { jbeg = 0; jinc = 1; } else { jbeg = ky - 1; jinc = -1; } kcnt = 0; if ((consec == 1) && (boustr == 0)) { /* adjacent points in same column; each column same direction */ for (jcnt = jbeg; ((0 <= jcnt) && (jcnt < ky)); jcnt += jinc) { for (icnt = ibeg; ((0 <= icnt) && (icnt < kx)); icnt += iinc) { idxarr = ky * icnt + jcnt; fgrid[kcnt] = ingrid[idxarr]; kcnt++; } } } else if ((consec == 0) && (boustr == 0)) { /* adjacent points in same row; each row same direction */ for (jcnt = jbeg; ((0 <= jcnt) && (jcnt < ky)); jcnt += jinc) { for (icnt = ibeg; ((0 <= icnt) && (icnt < kx)); icnt += iinc) { idxarr = kx * jcnt + icnt; fgrid[kcnt] = ingrid[idxarr]; kcnt++; } } } else if ((consec == 1) && (boustr == 1)) { /* adjacent points in same column; each column alternates direction */ for (jcnt = jbeg; ((0 <= jcnt) && (jcnt < ky)); jcnt += jinc) { itmp = jcnt; if ((idrct == 1) && (kx % 2 == 0)) { itmp = ky - jcnt - 1; } for (icnt = ibeg; ((0 <= icnt) && (icnt < kx)); icnt += iinc) { idxarr = ky * icnt + itmp; fgrid[kcnt] = ingrid[idxarr]; itmp = (itmp != jcnt) ? jcnt : ky - jcnt - 1; /* toggle */ kcnt++; } } } else if ((consec == 0) && (boustr == 1)) { /* adjacent points in same row; each row alternates direction */ if (jdrct == 0) { if ((idrct == 0) && (ky % 2 == 0)) { ibeg = kx - 1; iinc = -1; } if ((idrct == 1) && (ky % 2 == 0)) { ibeg = 0; iinc = 1; } } for (jcnt = jbeg; ((0 <= jcnt) && (jcnt < ky)); jcnt += jinc) { for (icnt = ibeg; ((0 <= icnt) && (icnt < kx)); icnt += iinc) { idxarr = kx * jcnt + icnt; fgrid[kcnt] = ingrid[idxarr]; kcnt++; } ibeg = (ibeg != 0) ? 0 : kx - 1; /* toggle */ iinc = (iinc != 1) ? 1 : -1; /* toggle */ } } //else { logically dead code //fgrid = ingrid; //} return fgrid; } /** * bit position */ private int bitPos = 0; /** * bit buffer */ private int bitBuf = 0; /** * bit buffer size */ private int next = 0; /** * character 1 */ private int ch1 = 0; /** * character 2 */ private int ch2 = 0; /** * character 3 */ private int ch3 = 0; /** * character 4 */ private int ch4 = 0; /** * Convert bits (nb) to Unsigned Int . * * @param nb number of bits * @return int of BinaryDataSection section * @throws IOException */ private int bits2UInt(int nb) throws IOException { int bitsLeft = nb; int result = 0; if (bitPos == 0) { //bitBuf = raf.read(); getNextByte(); bitPos = 8; } while (true) { int shift = bitsLeft - bitPos; if (shift > 0) { // Consume the entire buffer result |= bitBuf << shift; bitsLeft -= bitPos; // Get the next byte from the RandomAccessFile //bitBuf = raf.read(); getNextByte(); bitPos = 8; } else { // Consume a portion of the buffer result |= bitBuf >> -shift; bitPos -= bitsLeft; bitBuf &= 0xff >> (8 - bitPos); // mask off consumed bits return result; } } // end while } // end bits2Int /** * Get the next byte * * @throws IOException problem reading the byte */ private void getNextByte() throws IOException { if (!needToSwap) { // Get the next byte from the RandomAccessFile bitBuf = rf.read(); } else { if (next == 3) { bitBuf = ch3; } else if (next == 2) { bitBuf = ch2; } else if (next == 1) { bitBuf = ch1; } else { ch1 = rf.read(); ch2 = rf.read(); ch3 = rf.read(); ch4 = rf.read(); bitBuf = ch4; next = 4; } next--; } } /** * Log a warning message * * @param message the warning message */ private void logWarning(String message) { log.warn(rf.getLocation() + ": " + message); } }