/*
* Copyright 1998-2010 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.grid.GridIndex;
import ucar.grid.GridRecord;
import ucar.unidata.io.RandomAccessFile;
import java.io.*;
import java.util.ArrayList;
import java.util.Iterator;
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"
};
/** grid header len */
private int khdrln = 0;
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 {
if ( !super.init(fullCheck)) {
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;
}
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<GempakGridRecord>();
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 (int i = 0; i < tmpList.size(); i++) {
GempakGridRecord gh = (GempakGridRecord) tmpList.get(i);
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
int icol = gridNumber;
if ((icol < 1) || (icol > dmLabel.kcol)) {
logWarning("bad grid number " + icol);
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 = (DMPart) 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
+ (icol - 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
int ipktyp = DM_RINT(isword);
return ipktyp;
}
/**
* Find the first grid with this name
*
* @param parm name of grid
*
* @return the grid header or null
*/
public GempakGridRecord findGrid(String parm) {
List gridList = gridIndex.getGridRecords();
if (gridList == null) {
return null;
}
for (int i = 0; i < gridList.size(); i++) {
GempakGridRecord gh = (GempakGridRecord) gridList.get(i);
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 = null;
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 static boolean useDP = true;
/**
* 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.
//
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);
GempakGrib2Data gemGrib2 = new GempakGrib2Data(rf);
float[] data = gemGrib2.getData(start, 0);
if (((iarray[3] >> 6) & 1) == 0) { // -y scanning - flip
data = gb2_ornt(iarray[1], iarray[2], iarray[3], data);
}
return data;
}
/**
* Print out the navibation 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() {
StringBuffer buf = new StringBuffer("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() {
StringBuffer buf = new StringBuffer("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 gridList = gridIndex.getGridRecords();
if (gridList == null) {
return;
}
System.out.println(
" NUM TIME1 TIME2 LEVL1 LEVL2 VCORD PARM");
for (Iterator iter = gridList.iterator(); iter.hasNext(); ) {
System.out.println(iter.next());
}
}
/**
* 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
*
* 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.
*
* gb2_ornt ( kx, ky, scan_mode, ingrid, fgrid, iret )
*
* 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
*
* Output parameters:
* *fgrid float Unpacked grid data
* *iret int Return code
* -40 = scan mode not implemented
*
* 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 {
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
* @throws IOException
* @return int of BinaryDataSection section
*/
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);
}
}