static public Index factory(int[] shape) {
    int rank = shape.length;
    switch (rank) {
      case 0:
        return new Index0D();
      case 1:
        return new Index1D(shape);
      case 2:
        return new Index2D(shape);
      case 3:
        return new Index3D(shape);
      case 4:
        return new Index4D(shape);
      case 5:
        return new Index5D(shape);
      case 6:
        return new Index6D(shape);
      case 7:
        return new Index7D(shape);
      default:
        return new Index(shape);
    }
  }

static public Index factory ( int [ ] shape ) { int rank = shape . length ; switch ( rank ) { case 0 : return new Index0D ( ) ; case 1 : return new Index1D ( shape ) ; case 2 : return new Index2D ( shape ) ; case 3 : return new Index3D ( shape ) ; case 4 : return new Index4D ( shape ) ; case 5 : return new Index5D ( shape ) ; case 6 : return new Index6D ( shape ) ; case 7 : return new Index7D ( shape ) ; default : return new Index ( shape ) ; } }

Generate a subclass of Index optimized for this array's rank

@param shape use this shape
@return a subclass of Index optimized for this array's rank

Generate a subclass of Index optimized for this array s rank


static private long computeStrides(int[] shape, int[] stride) {
    long product = 1;
    for (int ii = shape.length - 1; ii >= 0; ii--) {
      final int thisDim = shape[ii];
      if (thisDim < 0)
        continue; // ignore vlen
      stride[ii] = (int) product;
      product *= thisDim;
    }
    return product;
  }

static
private
long
computeStrides
(
int
[
]
shape
,
int
[
]
stride
)
{
long
product
=
1
;
for
(
int
ii
=
shape
.
length
1
;
ii
>=
0
;
ii
)
{
final
int
thisDim
=
shape
[
ii
]
;
if
(
thisDim
<
0
)
continue
;
// ignore vlen
stride
[
ii
]
=
(
int
)
product
;
product
*=
thisDim
;
}
return
product
;
}

Compute standard strides based on array's shape.
Ignore vlen

@param shape  length of array in each dimension.
@param stride put result here
@return standard strides based on array's shape.

Compute standard strides based on array s shape . Ignore vlen


Index section(List<Range> ranges) throws InvalidRangeException {

    // check ranges are valid
    if (ranges.size() != rank)
      throw new InvalidRangeException("Bad ranges [] length");
    for (int ii = 0; ii < rank; ii++) {
      Range r = ranges.get(ii);
      if (r == null)
        continue;
      if (r == Range.VLEN)
        continue;
      if ((r.first() < 0) || (r.first() >= shape[ii]))
        throw new InvalidRangeException("Bad range starting value at index " + ii + " == " + r.first());
      if ((r.last() < 0) || (r.last() >= shape[ii]))
        throw new InvalidRangeException("Bad range ending value at index " + ii + " == " + r.last());
    }

    int reducedRank = rank;
    for (Range r : ranges) {
      if ((r != null) && (r.length() == 1))
        reducedRank--;
    }
    Index newindex = Index.factory(reducedRank);
    newindex.offset = offset;

    // calc shape, size, and index transformations
    // calc strides into original (backing) store
    int newDim = 0;
    for (int ii = 0; ii < rank; ii++) {
      Range r = ranges.get(ii);
      if (r == null) {          // null range means use the whole original dimension
        newindex.shape[newDim] = shape[ii];
        newindex.stride[newDim] = stride[ii];
        //if (name != null) newindex.name[newDim] = name[ii];
        newDim++;
      } else if (r.length() != 1) {
        newindex.shape[newDim] = r.length();
        newindex.stride[newDim] = stride[ii] * r.stride();
        newindex.offset += stride[ii] * r.first();
        //if (name != null) newindex.name[newDim] = name[ii];
        newDim++;
      } else {
        newindex.offset += stride[ii] * r.first();   // constant due to rank reduction
      }
    }
    newindex.size = computeSize(newindex.shape);
    newindex.fastIterator = fastIterator && (newindex.size == size); // if equal, then its not a real subset, so can still use fastIterator
    newindex.precalc(); // any subclass-specific optimizations
    return newindex;
  }

create a new Index based on a subsection of this one, with rank reduction if
dimension length == 1.

@param ranges array of Ranges that specify the array subset.
Must be same rank as original Array.
A particular Range: 1) may be a subset; 2) may be null, meaning use entire Range.
@return new Index, with same or smaller rank as original.
@throws InvalidRangeException if ranges dont match current shape

create a new Index based on a subsection of this one with rank reduction if dimension length == 1 .


Index reduce() {
    Index c = this;
    for (int ii = 0; ii < rank; ii++)
      if (shape[ii] == 1) {  // do this on the first one you find
        Index newc = c.reduce(ii);
        return newc.reduce();  // any more to do?
      }
    return c;
  }

Index
reduce
(
)
{
Index
c
=
this
;
for
(
int
ii
=
0
;
ii
<
rank
;
ii
++
)
if
(
shape
[
ii
]
==
1
)
{
// do this on the first one you find
Index
newc
=
c
.
reduce
(
ii
)
;
return
newc
.
reduce
(
)
;
// any more to do?
}
return
c
;
}

Create a new Index based on current one by
eliminating any dimensions with length one.

@return the new Index

Create a new Index based on current one by eliminating any dimensions with length one .


Index reduce(int dim) {
    if ((dim < 0) || (dim >= rank))
      throw new IllegalArgumentException("illegal reduce dim " + dim);
    if (shape[dim] != 1)
      throw new IllegalArgumentException("illegal reduce dim " + dim + " : length != 1");

    Index newindex = Index.factory(rank - 1);
    newindex.offset = offset;
    int count = 0;
    for (int ii = 0; ii < rank; ii++) {
      if (ii != dim) {
        newindex.shape[count] = shape[ii];
        newindex.stride[count] = stride[ii];
        //if (name != null) newindex.name[count] = name[ii];

        count++;
      }
    }
    newindex.size = computeSize(newindex.shape);
    newindex.fastIterator = fastIterator;
    newindex.precalc();         // any subclass-specific optimizations
    return newindex;
  }

Create a new Index based on current one by
eliminating the specified dimension;

@param dim: dimension to eliminate: must be of length one, else IllegalArgumentException
@return the new Index

Create a new Index based on current one by eliminating the specified dimension ;


Index transpose(int index1, int index2) {
    if ((index1 < 0) || (index1 >= rank))
      throw new IllegalArgumentException();
    if ((index2 < 0) || (index2 >= rank))
      throw new IllegalArgumentException();

    Index newIndex = (Index) this.clone();
    newIndex.stride[index1] = stride[index2];
    newIndex.stride[index2] = stride[index1];
    newIndex.shape[index1] = shape[index2];
    newIndex.shape[index2] = shape[index1];
    /* if (name != null) {
      newIndex.name[index1] = name[index2];
      newIndex.name[index2] = name[index1];
    } */

    newIndex.fastIterator = false;
    newIndex.precalc(); // any subclass-specific optimizations
    return newIndex;
  }

create a new Index based on current one, except
transpose two of the indices.

@param index1 transpose these two indices
@param index2 transpose these two indices
@return new Index with transposed indices

create a new Index based on current one except transpose two of the indices .


Index permute(int[] dims) {
    if (dims.length != shape.length)
      throw new IllegalArgumentException();
    for (int dim : dims)
      if ((dim < 0) || (dim >= rank))
        throw new IllegalArgumentException();

    boolean isPermuted = false;
    Index newIndex = (Index) this.clone();
    for (int i = 0; i < dims.length; i++) {
      newIndex.stride[i] = stride[dims[i]];
      newIndex.shape[i] = shape[dims[i]];
      //if (name != null) newIndex.name[i] = name[dims[i]];
      if (i != dims[i]) isPermuted = true;
    }

    newIndex.fastIterator = fastIterator && !isPermuted; // useful optimization
    newIndex.precalc(); // any subclass-specific optimizations
    return newIndex;
  }

create a new Index based on a permutation of the current indices; vlen fails.

@param dims: the old index dim[k] becomes the new kth index.
@return new Index with permuted indices

create a new Index based on a permutation of the current indices ; vlen fails .


IndexIterator getIndexIterator(Array maa) {
    if (fastIterator)
      return new IteratorFast(size, maa);
    else
      return new IteratorImpl(maa);
  }

IndexIterator getIndexIterator ( Array maa ) { if ( fastIterator ) return new IteratorFast ( size , maa ) ; else return new IteratorImpl ( maa ) ; }

Get an index iterator for traversing the array in canonical order.

@param maa the array to iterate through
@return an index iterator for traversing the array in canonical order.
@see IndexIterator

Get an index iterator for traversing the array in canonical order .


public int currentElement() {
    int value = offset;                 // NB: dont have to check each index again
    for (int ii = 0; ii < rank; ii++) { // general rank
      if (shape[ii] < 0) break;//vlen
      value += current[ii] * stride[ii];
    }
    return value;
  }

Get the current element's index into the 1D backing array.
VLEN stops processing.

@return the current element's index into the 1D backing array.

Get the current element s index into the 1D backing array . VLEN stops processing .


public Index set(int[] index) {
    if (index.length != rank)
      throw new ArrayIndexOutOfBoundsException();
    if (rank == 0) return this;
    int prefixrank = (hasvlen ? rank : rank - 1);
    System.arraycopy(index, 0, current, 0, prefixrank);
    if (hasvlen) current[prefixrank] = -1;
    return this;
  }

public Index set ( int [ ] index ) { if ( index . length != rank ) throw new ArrayIndexOutOfBoundsException ( ) ; if ( rank == 0 ) return this ; int prefixrank = ( hasvlen ? rank : rank - 1 ) ; System . arraycopy ( index , 0 , current , 0 , prefixrank ) ; if ( hasvlen ) current [ prefixrank ] = - 1 ; return this ; }

Set the current element's index. General-rank case.

@param index set current value to these values
@return this, so you can use A.get(i.set(i))
@throws ArrayIndexOutOfBoundsException if index.length != rank.

Set the current element s index . General - rank case .


public void setDim(int dim, int value) {
    if (value < 0 || value >= shape[dim])  // check index here
      throw new ArrayIndexOutOfBoundsException();
    if (shape[dim] >= 0) //!vlen
      current[dim] = value;
  }

public
void
setDim
(
int
dim
,
int
value
)
{
if
(
value
<
0
||
value
>=
shape
[
dim
]
)
// check index here
throw
new
ArrayIndexOutOfBoundsException
(
)
;
if
(
shape
[
dim
]
>=
0
)
//!vlen
current
[
dim
]
=
value
;
}

set current element at dimension dim to v

@param dim   set this dimension
@param value to this value


public Index set(int v0, int v1, int v2) {
    setDim(0, v0);
    setDim(1, v1);
    setDim(2, v2);
    return this;
  }

public Index set ( int v0 , int v1 , int v2 ) { setDim ( 0 , v0 ) ; setDim ( 1 , v1 ) ; setDim ( 2 , v2 ) ; return this ; }

set current element at dimension 0,1,2 to v0,v1,v2

@param v0 set dimension 0 index to this value
@param v1 set dimension 1 index to this value
@param v2 set dimension 2 index to this value
@return this, so you can use A.get(i.set(i,j,k))


public String getTimeIntervalName() {
    // are they the same length ?
    int firstValue = -1;
    for (TimeCoordIntvValue tinv : timeIntervals) {
      int value = (tinv.getBounds2() - tinv.getBounds1());
      if (firstValue < 0) firstValue = value;
      else if (value != firstValue) return MIXED_INTERVALS;
    }

    firstValue = (firstValue * timeUnit.getValue());
    return firstValue + "_" + timeUnit.getField().toString();
  }

public
String
getTimeIntervalName
(
)
{
// are they the same length ?
int
firstValue
=
1
;
for
(
TimeCoordIntvValue
tinv
:
timeIntervals
)
{
int
value
=
(
tinv
.
getBounds2
(
)
tinv
.
getBounds1
(
)
)
;
if
(
firstValue
<
0
)
firstValue
=
value
;
else
if
(
value
!=
firstValue
)
return
MIXED_INTERVALS
;
}
firstValue
=
(
firstValue
*
timeUnit
.
getValue
(
)
)
;
return
firstValue
+
"_"
+
timeUnit
.
getField
(
)
.
toString
(
)
;
}

Check if we all time intervals have the same length.
@return time interval name or MIXED_INTERVALS

Check if we all time intervals have the same length .


@Override
  public CalendarDateRange makeCalendarDateRange(ucar.nc2.time.Calendar cal) {
    CalendarDateUnit cdu = CalendarDateUnit.of(cal, timeUnit.getField(), refDate);
    CalendarDate start = cdu.makeCalendarDate( timeUnit.getValue() * timeIntervals.get(0).getBounds2());
    CalendarDate end = cdu.makeCalendarDate(timeUnit.getValue() * timeIntervals.get(getSize()-1).getBounds2());
    return CalendarDateRange.of(start, end);
  }

@ Override public CalendarDateRange makeCalendarDateRange ( ucar . nc2 . time . Calendar cal ) { CalendarDateUnit cdu = CalendarDateUnit . of ( cal , timeUnit . getField ( ) , refDate ) ; CalendarDate start = cdu . makeCalendarDate ( timeUnit . getValue ( ) * timeIntervals . get ( 0 ) . getBounds2 ( ) ) ; CalendarDate end = cdu . makeCalendarDate ( timeUnit . getValue ( ) * timeIntervals . get ( getSize ( ) - 1 ) . getBounds2 ( ) ) ; return CalendarDateRange . of ( start , end ) ; }

Make calendar date range, using the first and last ending bounds
@param cal  optional calendar, may be null
@return  calendar date range

Make calendar date range using the first and last ending bounds


protected List<String> makeDateList(boolean unique) {
    Key date = dateTimeKeys.get(0);
    Key time = dateTimeKeys.get(1);
    List<int[]> toCheck;
    if (date.type.equals(ROW)) {
      toCheck = headers.rowHeaders;
    } else {
      toCheck = headers.colHeaders;
    }
    List<String> fileDates = new ArrayList<>();
    for (int[] header : toCheck) {
      if (header[0] != IMISSD) {
        // convert to GEMPAK date/time
        int idate = header[date.loc + 1];
        int itime = header[time.loc + 1];
        // TODO: Add in the century
        String dateTime = GempakUtil.TI_CDTM(idate, itime);
        fileDates.add(dateTime);
      }
    }
    if (unique && !fileDates.isEmpty()) {
      SortedSet<String> uniqueTimes =
              Collections.synchronizedSortedSet(new TreeSet<String>());
      uniqueTimes.addAll(fileDates);
      fileDates.clear();
      fileDates.addAll(uniqueTimes);
    }

    return fileDates;
  }

protected
List
<
String
>
makeDateList
(
boolean
unique
)
{
Key
date
=
dateTimeKeys
.
get
(
0
)
;
Key
time
=
dateTimeKeys
.
get
(
1
)
;
List
<
int
[
]
>
toCheck
;
if
(
date
.
type
.
equals
(
ROW
)
)
{
toCheck
=
headers
.
rowHeaders
;
}
else
{
toCheck
=
headers
.
colHeaders
;
}
List
<
String
>
fileDates
=
new
ArrayList
<>
(
)
;
for
(
int
[
]
header
:
toCheck
)
{
if
(
header
[
0
]
!=
IMISSD
)
{
// convert to GEMPAK date/time
int
idate
=
header
[
date
.
loc
+
1
]
;
int
itime
=
header
[
time
.
loc
+
1
]
;
// TODO: Add in the century
String
dateTime
=
GempakUtil
.
TI_CDTM
(
idate
,
itime
)
;
fileDates
.
add
(
dateTime
)
;
}
}
if
(
unique
&&
!
fileDates
.
isEmpty
(
)
)
{
SortedSet
<
String
>
uniqueTimes
=
Collections
.
synchronizedSortedSet
(
new
TreeSet
<
String
>
(
)
)
;
uniqueTimes
.
addAll
(
fileDates
)
;
fileDates
.
clear
(
)
;
fileDates
.
addAll
(
uniqueTimes
)
;
}
return
fileDates
;
}

Get the list of dates

@param unique true for unique list
@return the list of dates


private List<GempakParameter> makeParams(DMPart part) {
    List<GempakParameter> gemparms = new ArrayList<>(part.kparms);
    for (DMParam param : part.params) {
      String name = param.kprmnm;
      GempakParameter parm = GempakParameters.getParameter(name);
      if (parm == null) {
        //System.out.println("couldn't find " + name
        //                   + " in params table");
        parm = new GempakParameter(1, name, name, "", 0);
      }
      gemparms.add(parm);
    }
    return gemparms;
  }

//                   + " in params table");

Make GempakParameters from the list of

@param part the part to use
@return parameters from the info in that part.


private List<GempakStation> getStationList() {
    Key slat = findKey(GempakStation.SLAT);
    if (slat == null) {
      return null;
    }
    List<int[]> toCheck;
    if (slat.type.equals(ROW)) {
      toCheck = headers.rowHeaders;
    } else {
      toCheck = headers.colHeaders;
    }
    List<GempakStation> fileStations = new ArrayList<>();
    int i = 0;
    for (int[] header : toCheck) {
      if (header[0] != IMISSD) {
        GempakStation station = makeStation(header);
        if (station != null) {
          station.setIndex(i + 1);
          fileStations.add(station);
        }
      }
      i++;
    }
    return fileStations;
  }

private List < GempakStation > getStationList ( ) { Key slat = findKey ( GempakStation . SLAT ) ; if ( slat == null ) { return null ; } List < int [ ] > toCheck ; if ( slat . type . equals ( ROW ) ) { toCheck = headers . rowHeaders ; } else { toCheck = headers . colHeaders ; } List < GempakStation > fileStations = new ArrayList <> ( ) ; int i = 0 ; for ( int [ ] header : toCheck ) { if ( header [ 0 ] != IMISSD ) { GempakStation station = makeStation ( header ) ; if ( station != null ) { station . setIndex ( i + 1 ) ; fileStations . add ( station ) ; } } i ++ ; } return fileStations ; }

Get the station list

@return the list of stations


private GempakStation makeStation(int[] header) {
    if ((stationKeys == null) || stationKeys.isEmpty()) {
      return null;
    }
    GempakStation newStation = new GempakStation();
    for (Key key : stationKeys) {
      int loc = key.loc + 1;
      switch (key.name) {
        case GempakStation.STID:
          newStation.setSTID(GempakUtil.ST_ITOC(header[loc]).trim());
          break;
        case GempakStation.STNM:
          newStation.setSTNM(header[loc]);
          break;
        case GempakStation.SLAT:
          newStation.setSLAT(header[loc]);
          break;
        case GempakStation.SLON:
          newStation.setSLON(header[loc]);
          break;
        case GempakStation.SELV:
          newStation.setSELV(header[loc]);
          break;
        case GempakStation.SPRI:
          newStation.setSPRI(header[loc]);
          break;
        case GempakStation.STAT:
          newStation.setSTAT(GempakUtil.ST_ITOC(header[loc]).trim());
          break;
        case GempakStation.COUN:
          newStation.setCOUN(GempakUtil.ST_ITOC(header[loc]).trim());
          break;
        case GempakStation.SWFO:
          newStation.setSWFO(GempakUtil.ST_ITOC(header[loc]).trim());
          break;
        case GempakStation.WFO2:
          newStation.setWFO2(GempakUtil.ST_ITOC(header[loc]).trim());
          break;
        case GempakStation.STD2:
          newStation.setSTD2(GempakUtil.ST_ITOC(header[loc]).trim());
          break;
      }
    }
    return newStation;
  }

private GempakStation makeStation ( int [ ] header ) { if ( ( stationKeys == null ) || stationKeys . isEmpty ( ) ) { return null ; } GempakStation newStation = new GempakStation ( ) ; for ( Key key : stationKeys ) { int loc = key . loc + 1 ; switch ( key . name ) { case GempakStation . STID : newStation . setSTID ( GempakUtil . ST_ITOC ( header [ loc ] ) . trim ( ) ) ; break ; case GempakStation . STNM : newStation . setSTNM ( header [ loc ] ) ; break ; case GempakStation . SLAT : newStation . setSLAT ( header [ loc ] ) ; break ; case GempakStation . SLON : newStation . setSLON ( header [ loc ] ) ; break ; case GempakStation . SELV : newStation . setSELV ( header [ loc ] ) ; break ; case GempakStation . SPRI : newStation . setSPRI ( header [ loc ] ) ; break ; case GempakStation . STAT : newStation . setSTAT ( GempakUtil . ST_ITOC ( header [ loc ] ) . trim ( ) ) ; break ; case GempakStation . COUN : newStation . setCOUN ( GempakUtil . ST_ITOC ( header [ loc ] ) . trim ( ) ) ; break ; case GempakStation . SWFO : newStation . setSWFO ( GempakUtil . ST_ITOC ( header [ loc ] ) . trim ( ) ) ; break ; case GempakStation . WFO2 : newStation . setWFO2 ( GempakUtil . ST_ITOC ( header [ loc ] ) . trim ( ) ) ; break ; case GempakStation . STD2 : newStation . setSTD2 ( GempakUtil . ST_ITOC ( header [ loc ] ) . trim ( ) ) ; break ; } } return newStation ; }

Make a station from the header info

@param header the station header
@return the corresponding station


public List<String> getStationKeyNames() {
    List<String> keys = new ArrayList<>();
    if ((stationKeys != null) && !stationKeys.isEmpty()) {
      for (Key key : stationKeys) {
        keys.add(key.name);
      }
    }
    return keys;
  }

public List < String > getStationKeyNames ( ) { List < String > keys = new ArrayList <> ( ) ; if ( ( stationKeys != null ) && ! stationKeys . isEmpty ( ) ) { for ( Key key : stationKeys ) { keys . add ( key . name ) ; } } return keys ; }

Get the station key names

@return the list of station key names


public List<Date> getDates() {
    if ((dates == null || dates.isEmpty()) && !dateList.isEmpty()) {
      dates = new ArrayList<>(dateList.size());
      dateFmt.setTimeZone(TimeZone.getTimeZone("GMT"));
      for (String dateString : dateList) {
        Date d = dateFmt.parse(dateString, new ParsePosition(0));
        //DateFromString.getDateUsingSimpleDateFormat(dateString,
        //    DATE_FORMAT);
        dates.add(d);
      }
    }
    return dates;
  }

Get the list of dates in this file.

@return list of dates.


public int findStationIndex(String id) {
    for (GempakStation station : getStations()) {
      if (station.getSTID().equals(id)) {
        return station.getIndex();
      }
    }
    return -1;
  }

public int findStationIndex ( String id ) { for ( GempakStation station : getStations ( ) ) { if ( station . getSTID ( ) . equals ( id ) ) { return station . getIndex ( ) ; } } return - 1 ; }

Find the station index for the specified station id.

@param id station id (case sensitive)
@return index or -1 if not found.

Find the station index for the specified station id .


public String getFileType() {
    String type = "Unknown";
    switch (dmLabel.kftype) {

      case MFSN:
        type = "Sounding";
        break;

      case MFSF:
        type = "Surface";
        break;

      default:
    }
    if (!subType.equals("")) {
      type = type + " (" + subType + ")";
    }
    return type;
  }

public
String
getFileType
(
)
{
String
type
=
"Unknown"
;
switch
(
dmLabel
.
kftype
)
{
case
MFSN
:
type
=
"Sounding"
;
break
;
case
MFSF
:
type
=
"Surface"
;
break
;
default
:
}
if
(
!
subType
.
equals
(
""
)
)
{
type
=
type
+
" ("
+
subType
+
")"
;
}
return
type
;
}

Get the type for this file

@return file type


public void indent(int n)
    {
        depth += n;
        if(depth < 0)
            depth = 0;
        else if(depth > MAXDEPTH)
            depth = MAXDEPTH;
    }

public void indent ( int n ) { depth += n ; if ( depth < 0 ) depth = 0 ; else if ( depth > MAXDEPTH ) depth = MAXDEPTH ; }

Set depth += n

@param n depth increment/decrement(if neg)


public void setIndent(int n)
    {
        depth = n;
        if(depth < 0)
            depth = 0;
        else if(depth > MAXDEPTH)
            depth = MAXDEPTH;
    }

public void setIndent ( int n ) { depth = n ; if ( depth < 0 ) depth = 0 ; else if ( depth > MAXDEPTH ) depth = MAXDEPTH ; }


public static GribIndex readOrCreateIndexFromSingleFile(boolean isGrib1, MFile mfile, CollectionUpdateType force, org.slf4j.Logger logger) throws IOException {

    GribIndex index = isGrib1 ? new Grib1Index() : new Grib2Index();

    if (!index.readIndex(mfile.getPath(), mfile.getLastModified(), force)) { // heres where the index date is checked against the data file
      index.makeIndex(mfile.getPath(), null);
      logger.debug("  Index written: {} == {} records", mfile.getName() + GBX9_IDX, index.getNRecords());
    } else if (debug) {
      logger.debug("  Index read: {} == {} records", mfile.getName() + GBX9_IDX, index.getNRecords());
    }

    return index;
  }

Create a gbx9 index from a single grib1 or grib2 file.
Use the existing index if it already exists.

@param isGrib1 true if grib1
@param mfile the grib file
@param force  force writing index
@return the resulting GribIndex
@throws IOException on io error

Create a gbx9 index from a single grib1 or grib2 file . Use the existing index if it already exists .


public void addDirectoryScan(String dirName, String suffix, String regexpPatternString, String subdirsS, String olderS, Object auxInfo) {
    CompositeMFileFilter filters = new CompositeMFileFilter();
    if (null != regexpPatternString)
      filters.addIncludeFilter(new RegExpMatchOnName(regexpPatternString));
    else if (suffix != null)
      filters.addIncludeFilter(new WildcardMatchOnPath("*" + suffix + "$"));

    if (olderS != null) {
      try {
        TimeDuration tu = new TimeDuration(olderS);
        filters.addAndFilter(new LastModifiedLimit((long) (1000 * tu.getValueInSeconds())));
      } catch (Exception e) {
        logger.error(collectionName + ": Invalid time unit for olderThan = {}", olderS);
      }
    }

    boolean wantSubdirs = true;
    if ((subdirsS != null) && subdirsS.equalsIgnoreCase("false"))
      wantSubdirs = false;

    CollectionConfig mc = new CollectionConfig(dirName, dirName, wantSubdirs, filters, auxInfo);

    // create name
    StringBuilder sb = new StringBuilder(dirName);
    if (wantSubdirs)
      sb.append("**/");
    if (null != regexpPatternString)
      sb.append(regexpPatternString);
    else if (suffix != null)
      sb.append(suffix);
    else
      sb.append("noFilter");

    collectionName = sb.toString();
    scanList.add(mc);
  }

Add a directory scan to the collection

@param dirName             scan this directory
@param suffix              require this suffix (overriddden by regexp), may be null
@param regexpPatternString if present, use this reqular expression to filter files , may be null
@param subdirsS            if "true", descend into subdirectories, may be null
@param olderS              udunit time unit - files must be older than this amount of time (now - lastModified > olderTime), may be null
// * @param dateFormatString dateFormatMark string, may be null
@param auxInfo             attach this object to any MFile found by this scan


@Override
  public boolean isScanNeeded() {
    // see if we need to recheck
    if (recheck == null) {
      logger.debug("{}: scan not needed, recheck null", collectionName);
      return false;
    }

    if (!hasScans()) {
      logger.debug("{}: scan not needed, no scanners", collectionName);
      return false;
    }

    synchronized (this) {
      if (map == null && !isStatic()) {
        logger.debug("{}: scan needed, never scanned", collectionName);
        return true;
      }
    }

    Date now = new Date();
    Date lastCheckedDate = new Date(getLastScanned());
    Date need = recheck.add(lastCheckedDate);
    if (now.before(need)) {
      logger.debug("{}: scan not needed, last scanned={}, now={}", collectionName, lastCheckedDate, now);
      return false;
    }

    return true;
  }

Compute if synchronous scan is needed.
True if recheck is true and enough time has elapsed.
@return true if rescan is needed

Compute if synchronous scan is needed . True if recheck is true and enough time has elapsed .


private boolean scanFirstTime() throws IOException {
    Map<String, MFile> newMap = new HashMap<>();
    if (!hasScans()) {
        map = newMap;
        return false;
    }

    reallyScan(newMap);
    // deleteOld(newMap); // ?? hmmmmm LOOK this seems wrong; maintainence in background ?? generally collection doesnt exist

    // implement olderThan
    if (olderThanInMsecs > 0) {
      long olderThan = System.currentTimeMillis() - olderThanInMsecs; // new files must be older than this.
      Iterator<MFile> iter = newMap.values().iterator(); // need iterator so we can remove()
      while (iter.hasNext()) {
        MFile newFile = iter.next();
        String path = newFile.getPath();
        if (newFile.getLastModified() > olderThan) { // the file is too new
          iter.remove();
          logger.debug("{}: scan found new Dataset but its too recently modified = {}", collectionName, path);
        }
      }
    }

    map = newMap;
    this.lastScanned = System.currentTimeMillis();
    this.lastChanged.set(this.lastScanned);
    logger.debug("{} : initial scan found n datasets = {} ", collectionName, map.keySet().size());
    return map.keySet().size() > 0;
  }


public static void setDebugFlags(ucar.nc2.util.DebugFlags debugFlags) {
    debug = debugFlags.isSet("ncfileWriter2/debug");
    debugWrite = debugFlags.isSet("ncfileWriter2/debugWrite");
    debugChunk = debugFlags.isSet("ncfileWriter2/debugChunk");
  }

public static void setDebugFlags ( ucar . nc2 . util . DebugFlags debugFlags ) { debug = debugFlags . isSet ( "ncfileWriter2/debug" ) ; debugWrite = debugFlags . isSet ( "ncfileWriter2/debugWrite" ) ; debugChunk = debugFlags . isSet ( "ncfileWriter2/debugChunk" ) ; }

Set debugging flags

@param debugFlags debug flags


public Variable addVariable(Variable oldVar) {
    List<Dimension> newDims = getNewDimensions(oldVar);

    Variable newVar;
    if ((oldVar.getDataType().equals(DataType.STRING)) && (!version.isExtendedModel())) {
      newVar = writer.addStringVariable(null, oldVar, newDims);
    } else {
      newVar = writer.addVariable(null, oldVar.getShortName(), oldVar.getDataType(), newDims);
    }
    varMap.put(oldVar, newVar);
    varList.add(oldVar);

    for (Attribute orgAtt : oldVar.getAttributes())
      writer.addVariableAttribute(newVar, convertAttribute(orgAtt));

    return newVar;
  }

public Variable addVariable ( Variable oldVar ) { List < Dimension > newDims = getNewDimensions ( oldVar ) ; Variable newVar ; if ( ( oldVar . getDataType ( ) . equals ( DataType . STRING ) ) && ( ! version . isExtendedModel ( ) ) ) { newVar = writer . addStringVariable ( null , oldVar , newDims ) ; } else { newVar = writer . addVariable ( null , oldVar . getShortName ( ) , oldVar . getDataType ( ) , newDims ) ; } varMap . put ( oldVar , newVar ) ; varList . add ( oldVar ) ; for ( Attribute orgAtt : oldVar . getAttributes ( ) ) writer . addVariableAttribute ( newVar , convertAttribute ( orgAtt ) ) ; return newVar ; }

Specify which variable will get written

@param oldVar add this variable, and all parent groups
@return new Variable.


public NetcdfFile write(CancelTask cancel) throws IOException {

    try {
      if (version.isExtendedModel())
        addGroupExtended(null, fileIn.getRootGroup());
      else
        addGroupClassic();

      if (cancel != null && cancel.isCancel()) return null;

      // create the file
      writer.create();

      if (cancel != null && cancel.isCancel()) return null;
      double total = copyVarData(varList, null, cancel);
      if (cancel != null && cancel.isCancel()) return null;

      writer.flush();
      if (debug) System.out.println("FileWriter done total bytes = " + total);

    } catch (IOException ioe) {
      ioe.printStackTrace();
      writer.abort();  // clean up
      throw ioe;
    }

    return writer.getNetcdfFile();
  }

public
NetcdfFile
write
(
CancelTask
cancel
)
throws
IOException
{
try
{
if
(
version
.
isExtendedModel
(
)
)
addGroupExtended
(
,
fileIn
.
getRootGroup
(
)
)
;
else
addGroupClassic
(
)
;
if
(
cancel
!=
&&
cancel
.
isCancel
(
)
)
return
;
// create the file
writer
.
create
(
)
;
if
(
cancel
!=
&&
cancel
.
isCancel
(
)
)
return
;
double
total
=
copyVarData
(
varList
,
,
cancel
)
;
if
(
cancel
!=
&&
cancel
.
isCancel
(
)
)
return
;
writer
.
flush
(
)
;
if
(
debug
)
System
.
out
.
println
(
"FileWriter done total bytes = "
+
total
)
;
}
catch
(
IOException
ioe
)
{
ioe
.
printStackTrace
(
)
;
writer
.
abort
(
)
;
// clean up
throw
ioe
;
}
return
writer
.
getNetcdfFile
(
)
;
}

Write the input file to the output file.
@param cancel  allow user to cancel; may be null.
@return the open output file.
@throws IOException

Write the input file to the output file .


public static void validate(XmlObject doc, boolean strict) throws XmlException {
        // Create an XmlOptions instance and set the error listener.
        Set<XmlError> validationErrors = new HashSet<>();
        XmlOptions validationOptions = new XmlOptions();
        validationOptions.setErrorListener(validationErrors);

        // Validate the XML document
        final boolean isValid = doc.validate(validationOptions);

        // Create Exception with error message if the xml document is invalid
        if (!isValid && !strict) {
            // check if we have special validation cases which could let the message pass anyhow
            validationErrors = filterToOnlySerious(validationErrors);
        }

        if (!validationErrors.isEmpty()) {
            throw new XmlException(createErrorMessage(validationErrors));
        }
    }

Validates an xml doc. If the validation fails, the exception contains a detailed list of errors.

@param doc the document to validate
@throws XmlException thrown if the XML is incorrect

Validates an xml doc . If the validation fails the exception contains a detailed list of errors .


@Override
    public String toConstraintString()
            throws DapException
    {
        assert this.first != UNDEFINED && this.stride != UNDEFINED && this.stop != UNDEFINED;
        StringBuilder buf = new StringBuilder();
        buf.append("[");
        boolean first = true;
        for(Slice sub: this.subslices) {
            if(!first) buf.append(",");
            first = false;
            if((sub.stop - sub.first) == 0) {
                buf.append("0");
            } else if(sub.stride == 1) {
                if((sub.stop - sub.first) == 1)
                    buf.append(sub.first);
                else
                    buf.append(String.format("%d:%d", sub.first, sub.stop - 1));
            } else
                buf.append(String.format("%d:%d:%d", sub.first, sub.stride, sub.stop - 1));
        }
        buf.append("]");
        return buf.toString();
    }

@ Override public String toConstraintString ( ) throws DapException { assert this . first != UNDEFINED && this . stride != UNDEFINED && this . stop != UNDEFINED ; StringBuilder buf = new StringBuilder ( ) ; buf . append ( "[" ) ; boolean first = true ; for ( Slice sub : this . subslices ) { if ( ! first ) buf . append ( "," ) ; first = false ; if ( ( sub . stop - sub . first ) == 0 ) { buf . append ( "0" ) ; } else if ( sub . stride == 1 ) { if ( ( sub . stop - sub . first ) == 1 ) buf . append ( sub . first ) ; else buf . append ( String . format ( "%d:%d" , sub . first , sub . stop - 1 ) ) ; } else buf . append ( String . format ( "%d:%d:%d" , sub . first , sub . stride , sub . stop - 1 ) ) ; } buf . append ( "]" ) ; return buf . toString ( ) ; }

Convert this multislice to a string
suitable for use in a constraint

@return constraint usable string
@throws DapException


public void setOriginalVariable(ucar.nc2.Variable orgVar) {
    if (!(orgVar instanceof Structure))
      throw new IllegalArgumentException("StructureDS must wrap a Structure; name=" + orgVar.getFullName());
    this.orgVar = (Structure) orgVar;
  }

Set the Structure to wrap.

@param orgVar original Variable, must be a Structure


@Override
  public Array reallyRead(Variable client, CancelTask cancelTask) throws IOException {
    Array result;

    if (hasCachedData())
      result = super.reallyRead(client, cancelTask);
    else if (orgVar != null)
      result = orgVar.read();
    else {
      throw new IllegalStateException("StructureDS has no way to get data");
      //Object data = smProxy.getFillValue(getDataType());
      //return Array.factoryConstant(dataType.getPrimitiveClassType(), getShape(), data);
    }

    return convert(result, null);
  }


@Override
  public Array reallyRead(Variable client, Section section, CancelTask cancelTask) throws IOException, InvalidRangeException {
    if (section.computeSize() == getSize())
      return _read();

    Array result;
    if (hasCachedData())
      result = super.reallyRead(client, section, cancelTask);
    else if (orgVar != null)
      result = orgVar.read(section);
    else {
      throw new IllegalStateException("StructureDS has no way to get data");
      //Object data = smProxy.getFillValue(getDataType());
      //return Array.factoryConstant(dataType.getPrimitiveClassType(), section.getShape(), data);
    }

    // do any needed conversions (enum/scale/offset/missing/unsigned, etc)
    return convert(result, section);
  }


private boolean convertNeeded(StructureMembers smData) {

    for (Variable v : getVariables()) {

      if (v instanceof VariableDS) {
        VariableDS vds = (VariableDS) v;
        if (vds.needConvert())
          return true;
      } else if (v instanceof StructureDS) {
        StructureDS nested = (StructureDS) v;
        if (nested.convertNeeded(null))
          return true;
      }

      // a variable with no data in the underlying smData
      if ((smData != null) && !varHasData(v, smData))
        return true;
    }

    return false;
  }


protected ArrayStructure convert(Array data, Section section) throws IOException {
    ArrayStructure orgAS = (ArrayStructure) data;
    if (!convertNeeded(orgAS.getStructureMembers())) {
      // name, info change only
      convertMemberInfo(orgAS.getStructureMembers());
      return orgAS;
    }

    // LOOK! converting to ArrayStructureMA
    // do any enum/scale/offset/missing/unsigned conversions
    ArrayStructure newAS = ArrayStructureMA.factoryMA(orgAS);
    for (StructureMembers.Member m : newAS.getMembers()) {
      VariableEnhanced v2 = (VariableEnhanced) findVariable(m.getName());
      if ((v2 == null) && (orgVar != null)) // these are from orgVar - may have been renamed
        v2 = findVariableFromOrgName(m.getName());
      if (v2 == null) continue;

      if (v2 instanceof VariableDS) {
        VariableDS vds = (VariableDS) v2;
        if (vds.needConvert()) {
          Array mdata = newAS.extractMemberArray(m);
          // mdata has not yet been enhanced, but vds would *think* that it has been if we used the 1-arg version of
          // VariableDS.convert(). So, we use the 2-arg version to explicitly request enhancement.
          mdata = vds.convert(mdata, vds.getEnhanceMode());
          newAS.setMemberArray(m, mdata);
        }

      } else if (v2 instanceof StructureDS) {
        StructureDS innerStruct = (StructureDS) v2;
        if (innerStruct.convertNeeded(null)) {

          if (innerStruct.getDataType() == DataType.SEQUENCE) {
            ArrayObject.D1 seqArray = (ArrayObject.D1) newAS.extractMemberArray(m);
            ArrayObject.D1 newSeq = (ArrayObject.D1) Array.factory(DataType.SEQUENCE, new int[] {(int) seqArray.getSize()});
            m.setDataArray(newSeq); // put back into member array

            // wrap each Sequence
            for (int i = 0; i < seqArray.getSize(); i++) {
              ArraySequence innerSeq = (ArraySequence) seqArray.get(i); // get old ArraySequence
              newSeq.set(i, new SequenceConverter(innerStruct, innerSeq)); // wrap in converter
            }

            // non-Sequence Structures
          } else {
            Array mdata = newAS.extractMemberArray(m);
            mdata = innerStruct.convert(mdata, null);
            newAS.setMemberArray(m, mdata);
          }

        }

        // always convert the inner StructureMembers
        innerStruct.convertMemberInfo(m.getStructureMembers());
      }
    }

    StructureMembers sm = newAS.getStructureMembers();
    convertMemberInfo(sm);

    // check for variables that have been added by NcML
    for (Variable v : getVariables()) {
      if (!varHasData(v, sm)) {
        try {
          Variable completeVar = getParentGroup().findVariable(v.getShortName()); // LOOK BAD
          Array mdata = completeVar.read(section);
          StructureMembers.Member m = sm.addMember(v.getShortName(), v.getDescription(), v.getUnitsString(), v.getDataType(), v.getShape());
          newAS.setMemberArray(m, mdata);
        } catch (InvalidRangeException e) {
          throw new IOException(e.getMessage());
        }
      }
    }

    return newAS;
  }

3) variable with cached data added to StructureDS through NcML

3 ) variable with cached data added to StructureDS through NcML


private void convertMemberInfo(StructureMembers wrapperSm) {
    for (StructureMembers.Member m : wrapperSm.getMembers()) {
      Variable v = findVariable(m.getName());
      if ((v == null) && (orgVar != null)) // may have been renamed
        v = (Variable) findVariableFromOrgName(m.getName());

      if (v != null) { // a section will have missing variables LOOK wrapperSm probably wrong in that case
        //  log.error("Cant find " + m.getName());
        //else
        m.setVariableInfo(v.getShortName(), v.getDescription(), v.getUnitsString(), v.getDataType());
      }

      // nested structures
      if (v instanceof StructureDS) {
        StructureDS innerStruct = (StructureDS) v;
        innerStruct.convertMemberInfo(m.getStructureMembers());
      }

    }
  }

the wrapper StructureMembers must be converted to correspond to the wrapper Structure


private VariableEnhanced findVariableFromOrgName(String orgName) {
    for (Variable vTop : getVariables()) {
      Variable v = vTop;
      while (v instanceof VariableEnhanced) {
        VariableEnhanced ve = (VariableEnhanced) v;
        if ((ve.getOriginalName() != null) && (ve.getOriginalName().equals(orgName)))
          return (VariableEnhanced) vTop;
        v = ve.getOriginalVariable();
      }
    }
    return null;
  }

private VariableEnhanced findVariableFromOrgName ( String orgName ) { for ( Variable vTop : getVariables ( ) ) { Variable v = vTop ; while ( v instanceof VariableEnhanced ) { VariableEnhanced ve = ( VariableEnhanced ) v ; if ( ( ve . getOriginalName ( ) != null ) && ( ve . getOriginalName ( ) . equals ( orgName ) ) ) return ( VariableEnhanced ) vTop ; v = ve . getOriginalVariable ( ) ; } } return null ; }

look for the top variable that has an orgVar with the wanted orgName


private boolean varHasData(Variable v, StructureMembers sm) {
    if (sm.findMember(v.getShortName()) != null) return true;
    while (v instanceof VariableEnhanced) {
      VariableEnhanced ve = (VariableEnhanced) v;
      if (sm.findMember(ve.getOriginalName()) != null) return true;
      v = ve.getOriginalVariable();
    }
    return false;
  }

private boolean varHasData ( Variable v , StructureMembers sm ) { if ( sm . findMember ( v . getShortName ( ) ) != null ) return true ; while ( v instanceof VariableEnhanced ) { VariableEnhanced ve = ( VariableEnhanced ) v ; if ( sm . findMember ( ve . getOriginalName ( ) ) != null ) return true ; v = ve . getOriginalVariable ( ) ; } return false ; }

verify that the variable has data in the data array


public void enhance(Set<NetcdfDataset.Enhance> mode) {
    for (Variable v : getVariables()) {
      VariableEnhanced ve = (VariableEnhanced) v;
      ve.enhance(mode);
    }
  }

public void enhance ( Set < NetcdfDataset . Enhance > mode ) { for ( Variable v : getVariables ( ) ) { VariableEnhanced ve = ( VariableEnhanced ) v ; ve . enhance ( mode ) ; } }

DO NOT USE DIRECTLY. public by accident.
recalc any enhancement info

DO NOT USE DIRECTLY . public by accident . recalc any enhancement info


public boolean resourceControlOk(HttpServletRequest req, HttpServletResponse res, String reqPath) {
    if (null == reqPath)
      reqPath = TdsPathUtils.extractPath(req, null);

    // see if its under resource control
    String rc = null;
    DataRootManager.DataRootMatch match = dataRootManager.findDataRootMatch(reqPath);
    if (match != null) {
      rc = match.dataRoot.getRestrict(); // datasetScan, featCollection are restricted at the dataRoot
    }

    if (rc == null) {
      rc = datasetTracker.findResourceControl(reqPath); // regular datasets tracked here
    }

    return resourceAuthorized(req, res, rc);
  }

Check if this is making a request for a restricted dataset, and if so, if its allowed.

@param req     the request
@param res     the response
@param reqPath the request path; if null, use req.getPathInfo()
@return true if ok to proceed. If false, the appropriate error or redirect message has been sent, the caller only needs to return.

Check if this is making a request for a restricted dataset and if so if its allowed .


private ArraySequence makeEmptySequence(Sequence seq) {
    StructureMembers members = seq.makeStructureMembers();
    return new ArraySequence(members, new EmptyStructureDataIterator(), -1);
  }

private ArraySequence makeEmptySequence ( Sequence seq ) { StructureMembers members = seq . makeStructureMembers ( ) ; return new ArraySequence ( members , new EmptyStructureDataIterator ( ) , - 1 ) ; }

Create an empty ArraySequence for missing data

@param seq the Sequence variable
@return the empty sequence


private ArraySequence makeArraySequence(Sequence seq, List<GempakParameter> params, float[] values) {

    if (values == null) {
      return makeEmptySequence(seq);
    }

    int numLevels = values.length / params.size();
    StructureMembers members = seq.makeStructureMembers();
    int offset = ArrayStructureBB.setOffsets(members);

    int size = offset * numLevels;
    byte[] bytes = new byte[size];
    ByteBuffer buf = ByteBuffer.wrap(bytes);
    ArrayStructureBB abb = new ArrayStructureBB(members, new int[]{numLevels}, buf, 0);
    int var = 0;
    for (int i = 0; i < numLevels; i++) {
      for (GempakParameter param : params) {
        if (members.findMember(param.getName()) != null) {
          buf.putFloat(values[var]);
        }
        var++;
      }
    }
    return new ArraySequence(members, new SequenceIterator(numLevels, abb), numLevels);
  }

private ArraySequence makeArraySequence ( Sequence seq , List < GempakParameter > params , float [ ] values ) { if ( values == null ) { return makeEmptySequence ( seq ) ; } int numLevels = values . length / params . size ( ) ; StructureMembers members = seq . makeStructureMembers ( ) ; int offset = ArrayStructureBB . setOffsets ( members ) ; int size = offset * numLevels ; byte [ ] bytes = new byte [ size ] ; ByteBuffer buf = ByteBuffer . wrap ( bytes ) ; ArrayStructureBB abb = new ArrayStructureBB ( members , new int [ ] { numLevels } , buf , 0 ) ; int var = 0 ; for ( int i = 0 ; i < numLevels ; i ++ ) { for ( GempakParameter param : params ) { if ( members . findMember ( param . getName ( ) ) != null ) { buf . putFloat ( values [ var ] ) ; } var ++ ; } } return new ArraySequence ( members , new SequenceIterator ( numLevels , abb ) , numLevels ) ; }

Create an ArraySequence to hold the data

@param seq    the Sequence variable
@param params the list of all GempakParameters possible in that sequence
@param values the values that were read
@return the ArraySequence


protected Sequence makeSequence(Structure parent, String partName, boolean includeMissing) {
    List<GempakParameter> params = gemreader.getParameters(partName);
    if (params == null) {
      return null;
    }
    Sequence sVar = new Sequence(ncfile, null, parent, partName);
    sVar.setDimensions("");
    for (GempakParameter param : params) {
      Variable v = makeParamVariable(param, null);
      addVerticalCoordAttribute(v);
      sVar.addMemberVariable(v);
    }
    if (includeMissing) {
      sVar.addMemberVariable(makeMissingVariable());
    }
    return sVar;
  }

protected Sequence makeSequence ( Structure parent , String partName , boolean includeMissing ) { List < GempakParameter > params = gemreader . getParameters ( partName ) ; if ( params == null ) { return null ; } Sequence sVar = new Sequence ( ncfile , null , parent , partName ) ; sVar . setDimensions ( "" ) ; for ( GempakParameter param : params ) { Variable v = makeParamVariable ( param , null ) ; addVerticalCoordAttribute ( v ) ; sVar . addMemberVariable ( v ) ; } if ( includeMissing ) { sVar . addMemberVariable ( makeMissingVariable ( ) ) ; } return sVar ; }

Make a Sequence for the part

@param parent         parent structure
@param partName       partname
@param includeMissing true to include the missing variable
@return a Structure


private void addVerticalCoordAttribute(Variable v) {

    GempakSoundingFileReader gsfr = (GempakSoundingFileReader) gemreader;
    int vertType = gsfr.getVerticalCoordinate();
    String pName = v.getFullName();
    if (gemreader.getFileSubType().equals(GempakSoundingFileReader.MERGED)) {
      if ((vertType == GempakSoundingFileReader.PRES_COORD) && pName.equals("PRES")) {
        v.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Pressure.name()));
      } else if ((vertType == GempakSoundingFileReader.HGHT_COORD) && (pName.equals("HGHT") || pName.equals("MHGT") || pName.equals("DHGT"))) {
        v.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Height.name()));
      }
    } else if (pName.equals("PRES")) {
      v.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Pressure.name()));
    }
  }

private void addVerticalCoordAttribute ( Variable v ) { GempakSoundingFileReader gsfr = ( GempakSoundingFileReader ) gemreader ; int vertType = gsfr . getVerticalCoordinate ( ) ; String pName = v . getFullName ( ) ; if ( gemreader . getFileSubType ( ) . equals ( GempakSoundingFileReader . MERGED ) ) { if ( ( vertType == GempakSoundingFileReader . PRES_COORD ) && pName . equals ( "PRES" ) ) { v . addAttribute ( new Attribute ( _Coordinate . AxisType , AxisType . Pressure . name ( ) ) ) ; } else if ( ( vertType == GempakSoundingFileReader . HGHT_COORD ) && ( pName . equals ( "HGHT" ) || pName . equals ( "MHGT" ) || pName . equals ( "DHGT" ) ) ) { v . addAttribute ( new Attribute ( _Coordinate . AxisType , AxisType . Height . name ( ) ) ) ; } } else if ( pName . equals ( "PRES" ) ) { v . addAttribute ( new Attribute ( _Coordinate . AxisType , AxisType . Pressure . name ( ) ) ) ; } }

Add the vertical coordinate variables if necessary

@param v the variable


public void readXMLasynch(String uriString, CatalogSetCallback callback) {
    InvCatalogImpl cat = readXML(uriString);
    callback.setCatalog(cat);
  }

public void readXMLasynch ( String uriString , CatalogSetCallback callback ) { InvCatalogImpl cat = readXML ( uriString ) ; callback . setCatalog ( cat ) ; }

This allows the possibility of reading a catalog in another thread. The default
implementation does not do that, but a subclass may override and implement.
If the catalog is read successfully, it is passed on to the callback.

@param uriString : read this catalog.
@param callback  : call this if successfully read.
@see CatalogSetCallback

This allows the possibility of reading a catalog in another thread . The default implementation does not do that but a subclass may override and implement . If the catalog is read successfully it is passed on to the callback .


public InvCatalogImpl readXML( String catAsString, URI baseUri )
  {
    return readXML( new StringReader( catAsString ), baseUri );
  }

public InvCatalogImpl readXML ( String catAsString , URI baseUri ) { return readXML ( new StringReader ( catAsString ) , baseUri ) ; }

Create an InvCatalog by reading catalog XML from a String.

Failures and exceptions are handled by causing validate() to
fail. Therefore, be sure to call validate() before trying to use
the InvCatalog object.

@param catAsString : the String from which to read the catalog.
@param baseUri : the base URI of the document, used for resolving reletive references.
@return an InvCatalogImpl object

Create an InvCatalog by reading catalog XML from a String .


public InvCatalogImpl readXML( StringReader catAsStringReader, URI baseUri )
  {
    XMLEntityResolver resolver = new XMLEntityResolver( false );
    SAXBuilder builder = resolver.getSAXBuilder();

    Document inDoc;
    try
    {
      inDoc = builder.build( catAsStringReader );
    }
    catch ( Exception e )
    {
      InvCatalogImpl cat = new InvCatalogImpl( baseUri.toString(), null, null );
      cat.appendErrorMessage( "**Fatal:  InvCatalogFactory.readXML(String catAsString, URI url) failed:"
                              + "\n  Exception= " + e.getClass().getName() + " " + e.getMessage()
                              + "\n  fatalMessages= " + fatalMessages.toString()
                              + "\n  errMessages= " + errMessages.toString()
                              + "\n  warnMessages= " + warnMessages.toString() + "\n", true );
      return cat;
    }

    return readXML( inDoc, baseUri );
  }

Create an InvCatalog by reading catalog XML from a StringReader.

Failures and exceptions are handled by causing validate() to
fail. Therefore, be sure to call validate() before trying to use
the InvCatalog object.

@param catAsStringReader : the StreamReader from which to read the catalog.
@param baseUri : the base URI of the document, used for resolving reletive references.
@return an InvCatalogImpl object

Create an InvCatalog by reading catalog XML from a StringReader .


public void writeXML(InvCatalogImpl catalog, OutputStream os, boolean raw) throws IOException {
    InvCatalogConvertIF converter = this.getCatalogConverter(XMLEntityResolver.CATALOG_NAMESPACE_10);
    converter.writeXML(catalog, os, raw);
  }

public void writeXML ( InvCatalogImpl catalog , OutputStream os , boolean raw ) throws IOException { InvCatalogConvertIF converter = this . getCatalogConverter ( XMLEntityResolver . CATALOG_NAMESPACE_10 ) ; converter . writeXML ( catalog , os , raw ) ; }

Write the InvCatalogImpl to the OutputStream as a InvCatalog 1.0 document.

@param catalog - the catalog to be written
@param os      - the OutputStream to write to
@param raw  if true, write raw, vs converted
@throws IOException           when the OutputStream can't be written
@throws IllegalStateException when the factory doesn't know how to write a 1.0 document.

Write the InvCatalogImpl to the OutputStream as a InvCatalog 1 . 0 document .


public MetadataConverterIF getMetadataConverter(String key) {
    if (key == null) return null;
    return metadataConverters.get(key);
  }

public MetadataConverterIF getMetadataConverter ( String key ) { if ( key == null ) return null ; return metadataConverters . get ( key ) ; }

Find the MetadataConverterIF registered for this key
@param key search on this key
@return  MetadataConverterIF else null


private static UnitName dimensionlessID() {
        UnitName id;
        try {
            id = UnitName.newUnitName("1", "1", "1");
        }
        catch (final NameException e) {
            id = null;
        }
        return id;
    }

private static UnitName dimensionlessID ( ) { UnitName id ; try { id = UnitName . newUnitName ( "1" , "1" , "1" ) ; } catch ( final NameException e ) { id = null ; } return id ; }

Returns the identifiers associated with the dimensionless, derived unit.

@return The identifiers of the dimensionless, derived unit.

Returns the identifiers associated with the dimensionless derived unit .


@Override
    protected Unit myMultiplyBy(final Unit that) throws MultiplyException {
        Unit result;
        if (dimension.getRank() == 0) {
            result = that;
        }
        else {
            if (!(that instanceof DerivedUnit)) {
                result = that.multiplyBy(this);
            }
            else {
                final UnitDimension thatDimension = ((DerivedUnit) that)
                        .getDimension();
                result = thatDimension.getRank() == 0
                        ? this
                        : new DerivedUnitImpl(dimension
                                .multiplyBy(thatDimension));
            }
        }
        return result;
    }

@ Override protected Unit myMultiplyBy ( final Unit that ) throws MultiplyException { Unit result ; if ( dimension . getRank ( ) == 0 ) { result = that ; } else { if ( ! ( that instanceof DerivedUnit ) ) { result = that . multiplyBy ( this ) ; } else { final UnitDimension thatDimension = ( ( DerivedUnit ) that ) . getDimension ( ) ; result = thatDimension . getRank ( ) == 0 ? this : new DerivedUnitImpl ( dimension . multiplyBy ( thatDimension ) ) ; } } return result ; }

Multiplies this derived unit by another.

@param that
The other unit.
@return The product of the two units.
@throws MultiplyException
Can't multiply these units.

Multiplies this derived unit by another .


@Override
    protected Unit myDivideBy(final Unit that) throws OperationException {
        Unit result;
        if (dimension.getRank() == 0) {
            result = that.raiseTo(-1);
        }
        else {
            if (!(that instanceof DerivedUnit)) {
                result = that.divideInto(this);
            }
            else {
                final UnitDimension thatDimension = ((DerivedUnit) that)
                        .getDimension();
                result = thatDimension.getRank() == 0
                        ? this
                        : new DerivedUnitImpl(dimension.divideBy(thatDimension));
            }
        }
        return result;
    }

@ Override protected Unit myDivideBy ( final Unit that ) throws OperationException { Unit result ; if ( dimension . getRank ( ) == 0 ) { result = that . raiseTo ( - 1 ) ; } else { if ( ! ( that instanceof DerivedUnit ) ) { result = that . divideInto ( this ) ; } else { final UnitDimension thatDimension = ( ( DerivedUnit ) that ) . getDimension ( ) ; result = thatDimension . getRank ( ) == 0 ? this : new DerivedUnitImpl ( dimension . divideBy ( thatDimension ) ) ; } } return result ; }

Divides this derived unit by another.

@param that
The other unit.
@return The quotient of the two units.
@throws OperationException
Can't divide these units.


public final float[] toDerivedUnit(final float[] input, final float[] output) {
        if (input != output) {
            System.arraycopy(input, 0, output, 0, input.length);
        }
        return output;
    }

public final float [ ] toDerivedUnit ( final float [ ] input , final float [ ] output ) { if ( input != output ) { System . arraycopy ( input , 0 , output , 0 , input . length ) ; } return output ; }

Converts numerical values from this unit to the derived unit. Obviously,
the numerical values are unchanged.

@param input
The numerical values in this unit.
@param output
The numerical values in the derived unit. May be the same
array as input.
@return output.

Converts numerical values from this unit to the derived unit . Obviously the numerical values are unchanged .


@Override
    public final boolean isCompatible(final Unit that) {
        final DerivedUnit unit = that.getDerivedUnit();
        return equals(unit) || isReciprocalOf(unit);
    }

@ Override public final boolean isCompatible ( final Unit that ) { final DerivedUnit unit = that . getDerivedUnit ( ) ; return equals ( unit ) || isReciprocalOf ( unit ) ; }

Indicates if values in this unit are convertible with another unit.

@param that
The other unit.
@return true if and only if values in this unit are
convertible to values in
that.

Indicates if values in this unit are convertible with another unit .


public String writeFeature(SimpleGeometry geom) {

        if (geom instanceof Point) return writePoint((Point)geom);
        else if (geom instanceof Line) return writeLine((Line)geom);
        else if (geom instanceof Polygon) return writePolygon((Polygon)geom);
        else return null;

    }

public String writeFeature ( SimpleGeometry geom ) { if ( geom instanceof Point ) return writePoint ( ( Point ) geom ) ; else if ( geom instanceof Line ) return writeLine ( ( Line ) geom ) ; else if ( geom instanceof Polygon ) return writePolygon ( ( Polygon ) geom ) ; else return null ; }

Checks the type of the Simple Geom and calls the appropriate method to build the xml

@param geom the Simple Geom
@return the xml


private String writePoint(Point point) {

        String xml = "";
        xml += "<gml:Point srsName=\"http://www.opengis.net/gml/srs/epsg.xml@900913\" srsDimension=\"2\">"
                + "<gml:pos>" + point.getX() + " " + point.getY() +"</gml:pos>"
                + "</gml:Point>";

        return xml;
    }

Takes in a point and writes its xml

@param point the point
@return the xml


private String writeLine(Line line) {

        String xml = "";
        xml += "<gml:LineString><gml:posList>";

        for (Point point: line.getPoints()) {
            xml += point.getX() + " " + point.getY() + " ";
        }

        xml += "</gml:posList></gml:LineString>";

        return xml;
    }

private
String
writeLine
(
Line
line
)
{
String
xml
=
""
;
xml
+=
"<gml:LineString><gml:posList>"
;
for
(
Point
point
:
line
.
getPoints
(
)
)
{
xml
+=
point
.
getX
(
)
+
" "
+
point
.
getY
(
)
+
" "
;
}
xml
+=
"</gml:posList></gml:LineString>"
;
return
xml
;
}

Takes in a line and iterates through all its points, writing the posList to xml

@param line the line
@return the xml

Takes in a line and iterates through all its points writing the posList to xml


private String writePolygon(Polygon poly) {

        String xml = "";
        xml += "<gml:Polygon>";

        Polygon polygon = poly;

    //    while (polygon != null) {

            if (!polygon.getInteriorRing()) {
                xml += "<gml:exterior><gml:LinearRing><gml:posList>";

                for (Point point : polygon.getPoints()) {
                    xml += point.getX() + " " + point.getY() + " ";
                }

                xml += "</gml:posList></gml:LinearRing></gml:exterior>";

            }

            else {
                xml += "<gml:interior><gml:LinearRing><gml:posList>";

                for (Point point : polygon.getPoints()) {
                    xml += point.getX() + " " + point.getY() + " ";
                }

                xml += "</gml:posList></gml:LinearRing></gml:interior>";
            }

      //      polygon = polygon.getNext();
       // }

        xml += "</gml:Polygon>";
        return xml;
    }

Takes in a polygon, checks whether it is an interior or exterior ring, and writes the corresponding xml.
Iterates through all linked polygons

@param polygon the polygon
@return the xml

Takes in a polygon checks whether it is an interior or exterior ring and writes the corresponding xml . Iterates through all linked polygons


protected String
    pull(Node n, String name)
    {
        NamedNodeMap map = n.getAttributes();
        Node attr = map.getNamedItem(name);
        if(attr == null)
            return null;
        return attr.getNodeValue();
    }

protected String pull ( Node n , String name ) { NamedNodeMap map = n . getAttributes ( ) ; Node attr = map . getNamedItem ( name ) ; if ( attr == null ) return null ; return attr . getNodeValue ( ) ; }


List<Node>
    getSubnodes(Node parent)
    {
        List<Node> subs = new ArrayList<>();
        NodeList nodes = parent.getChildNodes();
        for(int i = 0; i < nodes.getLength(); i++) {
            Node n = nodes.item(i);
            if(n.getNodeType() == Node.ELEMENT_NODE)
                subs.add(n);
        }
        return subs;
    }

List < Node > getSubnodes ( Node parent ) { List < Node > subs = new ArrayList <> ( ) ; NodeList nodes = parent . getChildNodes ( ) ; for ( int i = 0 ; i < nodes . getLength ( ) ; i ++ ) { Node n = nodes . item ( i ) ; if ( n . getNodeType ( ) == Node . ELEMENT_NODE ) subs . add ( n ) ; } return subs ; }

Return the subnodes of a node with non-element nodes suppressed

@param parent
@return list of element children

Return the subnodes of a node with non - element nodes suppressed


protected void
    parseresponse(Node root)
            throws ParseException
    {
        String elemname = root.getNodeName();
        if(elemname.equalsIgnoreCase("Error")) {
            parseerror(root);
        } else if(elemname.equalsIgnoreCase("Dataset")) {
            parsedataset(root);
        } else
            throw new ParseException("Unexpected response root: " + elemname);
    }

protected
void
parseresponse
(
Node
root
)
throws
ParseException
{
String
elemname
=
root
.
getNodeName
(
)
;
if
(
elemname
.
equalsIgnoreCase
(
"Error"
)
)
{
parseerror
(
root
)
;
}
else
if
(
elemname
.
equalsIgnoreCase
(
"Dataset"
)
)
{
parsedataset
(
root
)
;
}
else
throw
new
ParseException
(
"Unexpected response root: "
+
elemname
)
;
}


protected void
    passReserved(Node node, DapNode dap)
            throws ParseException
    {
        try {
            NamedNodeMap attrs = node.getAttributes();
            for(int i = 0; i < attrs.getLength(); i++) {
                Node n = attrs.item(i);
                String key = n.getNodeName();
                String value = n.getNodeValue();
                if(isReserved(key))
                    dap.addXMLAttribute(key, value);
            }
        } catch (DapException de) {
            throw new ParseException(de);
        }
    }

protected void passReserved ( Node node , DapNode dap ) throws ParseException { try { NamedNodeMap attrs = node . getAttributes ( ) ; for ( int i = 0 ; i < attrs . getLength ( ) ; i ++ ) { Node n = attrs . item ( i ) ; String key = n . getNodeName ( ) ; String value = n . getNodeValue ( ) ; if ( isReserved ( key ) ) dap . addXMLAttribute ( key , value ) ; } } catch ( DapException de ) { throw new ParseException ( de ) ; } }

Pass reserved xml attributes unchanged

@param node
@param dap
@throws ParseException


public static String getSubsetString(Variable var, int beginInd, int endInd, int id){
		if(var == null) return null;

		String subStr = "";

		List<Dimension> dimList = var.getDimensions();

		// Enforce two dimension arrays
		if(dimList.size() > 2 || dimList.size() < 1) {
			return null;
		}

		for(int i = 0; i < dimList.size(); i++) {

			Dimension dim = dimList.get(i);
			if(dim == null) continue;

			// If not CF Time then select only that ID
			if(!CF.TIME.equalsIgnoreCase(dim.getShortName()) && !CF.TIME.equalsIgnoreCase(dim.getFullNameEscaped())) {
				subStr += id;
			}

			// Otherwise subset based on time
			else {

				if(beginInd < 0 || endInd < 0) subStr += ":";
				else subStr += (beginInd + ":" + endInd);
			}

			if(i < dimList.size() - 1) {
				subStr += ",";
			}
		}

		return subStr;
	}

Gets the subset string  to be used in NetCDFFile.read given a variable and some indicies.
useful for subsetting timeseries

@param var variable to subset
@param beginInd beginning index (inclusive)
@param endInd end index (exclusive)
@param id The SimpleGeometryID to index
@return subset string

Gets the subset string to be used in NetCDFFile . read given a variable and some indicies . useful for subsetting timeseries


static public ArrayStructureMA factoryMA(ArrayStructure from) throws IOException {
    if (from instanceof ArrayStructureMA)
      return (ArrayStructureMA) from;

    // To create an ArrayStructureMA that we can iterate over later, we need to know the shape of "from".
    if (from.getSize() > 0) {
      ArrayStructureMA to = new ArrayStructureMA(new StructureMembers(from.getStructureMembers()), from.getShape());
      for (StructureMembers.Member m : from.getMembers()) {
        to.setMemberArray(m.getName(), from.extractMemberArray(m));
      }
      return to;
    }

    // from.getSize() <= 0. This usually means that "from" is an ArraySequence, and that we won't know its size until
    // we iterate over it. extractMemberArray() will do that iteration for us, and then we can use the size of the
    // array it returns to determine the shape of "from".

    int numRecords = -1;
    Map<String, Array> memberArrayMap = new LinkedHashMap<>();

    for (StructureMembers.Member m : from.getMembers()) {
      Array array = from.extractMemberArray(m);
      assert array.getSize() > 0 : "array's size should have been computed in extractMemberArray().";
      int firstDimLen = array.getShape()[0];

      if (numRecords == -1) {
        numRecords = firstDimLen;
      } else {
        assert numRecords == firstDimLen : String.format("Expected all structure members to have the same first" +
                "dimension length, but %d != %d.", numRecords, firstDimLen);
      }

      memberArrayMap.put(m.getName(), array);
    }

    int[] shape;
    if (numRecords == -1) {
      shape = new int[] { 0 };  // "from" really was empty.
    } else {
      shape = new int[] { numRecords };
    }

    ArrayStructureMA to = new ArrayStructureMA(new StructureMembers(from.getStructureMembers()), shape);

    for (Map.Entry<String, Array> entry : memberArrayMap.entrySet()) {
      to.setMemberArray(entry.getKey(), entry.getValue());
    }

    return to;
  }

Turn any ArrayStructure into a ArrayStructureMA
@param from copy from here. If from is a ArrayStructureMA, return it.
@return equivalent ArrayStructureMA
@throws java.io.IOException on error reading a sequence


public void setMemberArray( String memberName, Array data) {
    StructureMembers.Member m = members.findMember( memberName);
    m.setDataArray( data);
  }

public void setMemberArray ( String memberName , Array data ) { StructureMembers . Member m = members . findMember ( memberName ) ; m . setDataArray ( data ) ; }

Set the data array for this member.
@param memberName name of member
@param data Array for this member.


static public ArrayStructureMA factoryMA(Structure from, int[] shape) throws IOException {
    StructureMembers sm = from.makeStructureMembers();
    for (Variable v : from.getVariables()) {
      Array data;
      if (v instanceof Sequence) {
        data = Array.factory(DataType.SEQUENCE, shape);  // an array sequence - one for each parent element
        //Structure s = (Structure) v;
        //StructureMembers smn = s.makeStructureMembers();
        // data = new ArraySequenceNested(smn, (int) Index.computeSize(v.getShapeAll())); // ??

      } else if (v instanceof Structure)
        data = ArrayStructureMA.factoryMA((Structure) v, combine(shape, v.getShape()));

      else
        data = Array.factory(v.getDataType(), combine(shape, v.getShape()));

      StructureMembers.Member m = sm.findMember(v.getShortName());
      m.setDataArray(data);
    }

    return new ArrayStructureMA(sm, shape);
  }

Create an ArrayStructure for a Structure. Allow nested Structures.
Create the data arrays, and an iterator.

@param from copy from here. If from is a ArrayStructureMA, return it.
@param shape the shape of the ArrayStructure
@return equivilent ArrayStructureMA
@throws java.io.IOException on error reading a sequence

Create an ArrayStructure for a Structure . Allow nested Structures . Create the data arrays and an iterator .


public GeometryType getGeometryType(String name) {
		Variable geometryVar = ds.findVariable(name);
		if(geometryVar == null) return null;

		// CFConvention
		if(ds.findGlobalAttribute(CF.CONVENTIONS) != null)
			if(ucar.nc2.dataset.conv.CF1Convention.getVersion(ds.findGlobalAttribute(CF.CONVENTIONS).getStringValue()) >= 8)
			{
				Attribute geometryTypeAttr = null;
				String geometry_type = null;

				geometryTypeAttr = geometryVar.findAttribute(CF.GEOMETRY_TYPE);
				if(geometryTypeAttr == null) return null;
				geometry_type = geometryTypeAttr.getStringValue();

				switch(geometry_type)
				{
					case CF.POLYGON:
						return GeometryType.POLYGON;
					case CF.LINE:
						return GeometryType.LINE;
					case CF.POINT:
						return GeometryType.POINT;
					default:
						return null;
				}
			}

		return null;
	}

public
GeometryType
getGeometryType
(
String
name
)
{
Variable
geometryVar
=
ds
.
findVariable
(
name
)
;
if
(
geometryVar
==
)
return
;
// CFConvention
if
(
ds
.
findGlobalAttribute
(
CF
.
CONVENTIONS
)
!=
)
if
(
ucar
.
nc2
.
dataset
.
conv
.
CF1Convention
.
getVersion
(
ds
.
findGlobalAttribute
(
CF
.
CONVENTIONS
)
.
getStringValue
(
)
)
>=
8
)
{
Attribute
geometryTypeAttr
=
;
String
geometry_type
=
;
geometryTypeAttr
=
geometryVar
.
findAttribute
(
CF
.
GEOMETRY_TYPE
)
;
if
(
geometryTypeAttr
==
)
return
;
geometry_type
=
geometryTypeAttr
.
getStringValue
(
)
;
switch
(
geometry_type
)
{
case
CF
.
POLYGON
:
return
GeometryType
.
POLYGON
;
case
CF
.
LINE
:
return
GeometryType
.
LINE
;
case
CF
.
POINT
:
return
GeometryType
.
POINT
;
default
:
return
;
}
}
return
;
}

Given a variable name, returns the geometry type which that variable is associated with.
If the variable has no simple geometry information, null will be returned.

@param name variable name which will have geometry type be checked
@return Geometry Type if holds geometry information, null if not

Given a variable name returns the geometry type which that variable is associated with . If the variable has no simple geometry information null will be returned .


public StationTimeSeriesFeature makeStation(StructureData stationData, int recnum) {
    StationFeature s = ft.makeStation(stationData);
    if (s == null) return null;
    return new StandardStationFeatureImpl(s, timeUnit, stationData, recnum);
  }

public StationTimeSeriesFeature makeStation ( StructureData stationData , int recnum ) { StationFeature s = ft . makeStation ( stationData ) ; if ( s == null ) return null ; return new StandardStationFeatureImpl ( s , timeUnit , stationData , recnum ) ; }

Make a Station from the station data structure.

@param stationData station data structure
@param recnum      station data recnum within table
@return Station or null, skip this Station

Make a Station from the station data structure .


protected void
    compileAST(CEAST ast)
            throws DapException
    {
        switch (ast.sort) {
        case CONSTRAINT:
            for(CEAST clause : ast.clauses) {
                compileAST(clause);
            }
            // invoke semantic checks
            this.ce.expand();
            this.ce.finish();
            break;
        case PROJECTION:
            scopestack.clear();
            compileAST(ast.tree);
            break;
        case SEGMENT:
            compilesegment(ast);
            break;
        case SELECTION:
            scopestack.clear();
            compileselection(ast);
            break;
        case DEFINE:
            dimredef(ast);
            break;
        default:
            assert false : "uknown CEAST node type";
        }
    }

protected
void
compileAST
(
CEAST
ast
)
throws
DapException
{
switch
(
ast
.
sort
)
{
case
CONSTRAINT
:
for
(
CEAST
clause
:
ast
.
clauses
)
{
compileAST
(
clause
)
;
}
// invoke semantic checks
this
.
ce
.
expand
(
)
;
this
.
ce
.
finish
(
)
;
break
;
case
PROJECTION
:
scopestack
.
clear
(
)
;
compileAST
(
ast
.
tree
)
;
break
;
case
SEGMENT
:
compilesegment
(
ast
)
;
break
;
case
SELECTION
:
scopestack
.
clear
(
)
;
compileselection
(
ast
)
;
break
;
case
DEFINE
:
dimredef
(
ast
)
;
break
;
default
:
assert
false
:
"uknown CEAST node type"
;
}
}

Recursive AST walker; compilation of filters is done elsewhere.

Recursive AST walker ; compilation of filters is done elsewhere .


public void
    compilefilter(DapVariable var, DapSequence seq, CEAST expr)
            throws DapException
    {
        if(expr == null)
            return;
        if(expr.sort == CEAST.Sort.SEGMENT) {
            // This must be a simple segment and it must appear in seq
            if(expr.subnodes != null)
                throw new DapException("compilefilter: Non-simple segment:" + expr.name);
            // Look for the name in the top-level field of seq
            DapVariable field = seq.findByName(expr.name);
            if(field == null)
                throw new DapException("compilefilter: Unknown filter variable:" + expr.name);
            expr.field = field;
        } else if(expr.sort == CEAST.Sort.EXPR) {
            if(expr.lhs != null)
                compilefilter(var, seq, expr.lhs);
            if(expr.rhs != null)
                compilefilter(var, seq, expr.rhs);
            // If both lhs and rhs are non-null,
            // canonicalize any comparison so that it is var op const
            if(expr.lhs != null && expr.rhs != null) {
                boolean leftvar = (expr.lhs.sort == CEAST.Sort.SEGMENT);
                boolean rightvar = (expr.rhs.sort == CEAST.Sort.SEGMENT);

                if(rightvar && !leftvar) { // swap operands
                    CEAST tmp = expr.lhs;
                    expr.lhs = expr.rhs;
                    expr.rhs = tmp;
                    // fix operator
                    switch (expr.op) {
                    case LT:  //x<y -> y>x
                        expr.op = CEAST.Operator.GT;
                        break;
                    case LE: //x<=y -> y>=x
                        expr.op = CEAST.Operator.GE;
                        break;
                    case GT:  //x>y -> y<x
                        expr.op = CEAST.Operator.LT;
                        break;
                    case GE:   //x>=y -> y<=x
                        expr.op = CEAST.Operator.LE;
                        break;
                    default:
                        break; // leave as is
                    }
                }
            }
        } else if(expr.sort == CEAST.Sort.CONSTANT) {
            return;
        } else
            throw new DapException("compilefilter: Unexpected node type:" + expr.sort);
    }


protected void
    dimredef(CEAST node)
            throws DapException
    {
        DapDimension dim = (DapDimension) dataset.findByFQN(node.name, DapSort.DIMENSION);
        if(dim == null)
            throw new DapException("Constraint dim redef: no dimension name: " + node.name);
        Slice slice = node.slice;
        slice.finish();
        ce.addRedef(dim, slice);
    }


protected Array createView( Index index) {
    return ArrayObject.factory( dataType, elementType, isVlen, index, storage);
  }

protected Array createView ( Index index ) { return ArrayObject . factory ( dataType , elementType , isVlen , index , storage ) ; }

create new Array with given indexImpl and the same backing store


public boolean containedIn(LatLonRect b) {
    return (b.getWidth() >= width) && b.contains(upperRight)
        && b.contains(lowerLeft);
  }

public boolean containedIn ( LatLonRect b ) { return ( b . getWidth ( ) >= width ) && b . contains ( upperRight ) && b . contains ( lowerLeft ) ; }

Determine if this bounding box is contained in another LatLonRect.

@param b the other box to see if it contains this one
@return true if b contained in this bounding box

Determine if this bounding box is contained in another LatLonRect .


public void extend(LatLonPoint p) {
    if (contains(p))
      return;

    double lat = p.getLatitude();
    double lon = p.getLongitude();

    // lat is easy to deal with
    if (lat > upperRight.getLatitude()) {
      upperRight.setLatitude(lat);
    }
    if (lat < lowerLeft.getLatitude()) {
      lowerLeft.setLatitude(lat);
    }

    // lon is uglier
    if (allLongitude) {
      // do nothing
    } else if (crossDateline) {

      // bounding box crosses the +/- 180 seam
      double d1 = lon - upperRight.getLongitude();
      double d2 = lowerLeft.getLongitude() - lon;
      if ((d1 > 0.0) && (d2 > 0.0)) {  // needed ?
        if (d1 > d2) {
          lowerLeft.setLongitude(lon);
        } else {
          upperRight.setLongitude(lon);
        }
      }

    } else {

      // normal case
      if (lon > upperRight.getLongitude()) {
        if (lon - upperRight.getLongitude() > lowerLeft.getLongitude() - lon + 360) {
          crossDateline = true;
          lowerLeft.setLongitude(lon);
        } else {
          upperRight.setLongitude(lon);
        }
      } else if (lon < lowerLeft.getLongitude()) {
        if (lowerLeft.getLongitude() - lon > lon + 360.0 - upperRight.getLongitude()) {
          crossDateline = true;
          upperRight.setLongitude(lon);
        } else {
          lowerLeft.setLongitude(lon);
        }
      }
    }

    // recalc delta, center
    width = upperRight.getLongitude() - lowerLeft.getLongitude();
    lon0 = (upperRight.getLongitude() + lowerLeft.getLongitude()) / 2;
    if (crossDateline) {
      width += 360;
      lon0 -= 180;
    }

    this.allLongitude = this.allLongitude || (this.width >= 360.0);
  }

Extend the bounding box to contain this point

@param p point to include


public void extend(LatLonRect r) {
    Preconditions.checkNotNull(r);

    // lat is easy
    double latMin = r.getLatMin();
    double latMax = r.getLatMax();

    if (latMax > upperRight.getLatitude()) {
      upperRight.setLatitude(latMax);
    }
    if (latMin < lowerLeft.getLatitude()) {
      lowerLeft.setLatitude(latMin);
    }

    // lon is uglier
    if (allLongitude)
      return;

    // everything is reletive to current LonMin
    double lonMin = getLonMin();
    double lonMax = getLonMax();

    double nlonMin = LatLonPointImpl.lonNormal( r.getLonMin(), lonMin);
    double nlonMax = nlonMin + r.getWidth();
    lonMin = Math.min(lonMin, nlonMin);
    lonMax = Math.max(lonMax, nlonMax);

    width = lonMax - lonMin;
    allLongitude = width >= 360.0;
    if (allLongitude) {
      width = 360.0;
      lonMin = -180.0;
    } else {
      lonMin = LatLonPointImpl.lonNormal(lonMin);
    }

    lowerLeft.setLongitude(lonMin);
    upperRight.setLongitude(lonMin+width);
    lon0 = lonMin+width/2;
    crossDateline = lowerLeft.getLongitude() > upperRight.getLongitude();
  }

Extend the bounding box to contain the given rectangle

@param r rectangle to include


public LatLonRect intersect(LatLonRect clip) {
    double latMin = Math.max(getLatMin(), clip.getLatMin());
    double latMax = Math.min(getLatMax(), clip.getLatMax());
    double deltaLat = latMax - latMin;
    if (deltaLat < 0)
      return null;

    // lon as always is a pain : if not intersection, try +/- 360
    double lon1min = getLonMin();
    double lon1max = getLonMax();
    double lon2min = clip.getLonMin();
    double lon2max = clip.getLonMax();
    if (!intersect(lon1min, lon1max, lon2min, lon2max)) {
      lon2min = clip.getLonMin() + 360;
      lon2max = clip.getLonMax() + 360;
      if (!intersect(lon1min, lon1max, lon2min, lon2max)) {
        lon2min = clip.getLonMin() - 360;
        lon2max = clip.getLonMax() - 360;
      }
    }

    // we did our best to find an intersection
    double lonMin = Math.max(lon1min, lon2min);
    double lonMax = Math.min(lon1max, lon2max);
    double deltaLon = lonMax - lonMin;
    if (deltaLon < 0)
      return null;

    return new LatLonRect(new LatLonPointImpl(latMin, lonMin), deltaLat, deltaLon);
  }

Create the instersection of this LatLon with the given one

@param clip intersect with this
@return intersection, or null if there is no intersection


public static Array add(Array a, Array b) throws IllegalArgumentException {

    Array result = Array.factory(a.getDataType(), a.getShape());

    if (a.getElementType() == double.class) {
      addDouble(result, a, b);
    } else
      throw new UnsupportedOperationException();

    return result;
  }

public static Array add ( Array a , Array b ) throws IllegalArgumentException { Array result = Array . factory ( a . getDataType ( ) , a . getShape ( ) ) ; if ( a . getElementType ( ) == double . class ) { addDouble ( result , a , b ) ; } else throw new UnsupportedOperationException ( ) ; return result ; }

Add elements of two arrays together, allocating the result array.
The result type and the operation type are taken from the type of a.

@param a add values from here
@param b add values from here
@return result = a + b
@throws IllegalArgumentException      a and b are not conformable
@throws UnsupportedOperationException dont support this data type yet

Add elements of two arrays together allocating the result array . The result type and the operation type are taken from the type of a .


public static boolean conformable(Array a, Array b) {
    return conformable(a.getShape(), b.getShape());
  }

public static boolean conformable ( Array a , Array b ) { return conformable ( a . getShape ( ) , b . getShape ( ) ) ; }

Check that two arrays are conformable.

@param a operand
@param b operand
@return true if conformable


public static boolean conformable(int[] shapeA, int[] shapeB) {
    if (reducedRank(shapeA) != reducedRank(shapeB))
      return false;

    int rankB = shapeB.length;

    int dimB = 0;
    for (int aShapeA : shapeA) {
      //System.out.println(dimA + " "+ dimB);

      //skip length 1 dimensions
      if (aShapeA == 1)
        continue;
      while (dimB < rankB)
        if (shapeB[dimB] == 1) dimB++;
        else break;

      // test same shape (NB dimB cant be > rankB due to first test)
      if (aShapeA != shapeB[dimB])
        return false;
      dimB++;
    }

    return true;
  }

Check that two array shapes are conformable.
The shapes must match exactly, except that dimensions of length 1 are ignored.

@param shapeA shape of array 1
@param shapeB shape of array 2
@return true if conformable

Check that two array shapes are conformable . The shapes must match exactly except that dimensions of length 1 are ignored .


public static Array convert( Array org, DataType wantType) {
    if (org == null) return null;
    Class wantClass = wantType.getPrimitiveClassType();
    if (org.getElementType().equals(wantClass))
      return org;

    Array result = Array.factory(wantType, org.getShape());
    copy(wantType, org.getIndexIterator(), result.getIndexIterator());
    return result;
  }

public static Array convert ( Array org , DataType wantType ) { if ( org == null ) return null ; Class wantClass = wantType . getPrimitiveClassType ( ) ; if ( org . getElementType ( ) . equals ( wantClass ) ) return org ; Array result = Array . factory ( wantType , org . getShape ( ) ) ; copy ( wantType , org . getIndexIterator ( ) , result . getIndexIterator ( ) ) ; return result ; }

Convert original array to desired type

@param org original array
@param wantType desired type
@return converted data of desired type, or original array if it is already


public static void copy(Array result, Array a) throws IllegalArgumentException {
    Class classType = a.getElementType();
    if (classType == double.class) {
      copyDouble(result, a);
    } else if (classType == float.class) {
      copyFloat(result, a);
    } else if (classType == long.class) {
      copyLong(result, a);
    } else if (classType == int.class) {
      copyInt(result, a);
    } else if (classType == short.class) {
      copyShort(result, a);
    } else if (classType == char.class) {
      copyChar(result, a);
    } else if (classType == byte.class) {
      copyByte(result, a);
    } else if (classType == boolean.class) {
      copyBoolean(result, a);
    } else
      copyObject(result, a);
  }

public static void copy ( Array result , Array a ) throws IllegalArgumentException { Class classType = a . getElementType ( ) ; if ( classType == double . class ) { copyDouble ( result , a ) ; } else if ( classType == float . class ) { copyFloat ( result , a ) ; } else if ( classType == long . class ) { copyLong ( result , a ) ; } else if ( classType == int . class ) { copyInt ( result , a ) ; } else if ( classType == short . class ) { copyShort ( result , a ) ; } else if ( classType == char . class ) { copyChar ( result , a ) ; } else if ( classType == byte . class ) { copyByte ( result , a ) ; } else if ( classType == boolean . class ) { copyBoolean ( result , a ) ; } else copyObject ( result , a ) ; }

Copy array a to array result, the result array will be in canonical order
The operation type is taken from the type of a.

@param result copy to here
@param a copy from here

@throws IllegalArgumentException      a and b are not conformable
@throws UnsupportedOperationException dont support this data type yet

Copy array a to array result the result array will be in canonical order The operation type is taken from the type of a .


public static void copyBoolean(Array result, Array a) throws IllegalArgumentException {
    if (!conformable(a, result))
      throw new IllegalArgumentException("copy arrays are not conformable");

    IndexIterator iterA = a.getIndexIterator();
    IndexIterator iterR = result.getIndexIterator();
    while (iterA.hasNext())
      iterR.setBooleanNext(iterA.getBooleanNext());
  }

public
static
void
copyBoolean
(
Array
result
,
Array
a
)
throws
IllegalArgumentException
{
if
(
!
conformable
(
a
,
result
)
)
throw
new
IllegalArgumentException
(
"copy arrays are not conformable"
)
;
IndexIterator
iterA
=
a
.
getIndexIterator
(
)
;
IndexIterator
iterR
=
result
.
getIndexIterator
(
)
;
while
(
iterA
.
hasNext
(
)
)
iterR
.
setBooleanNext
(
iterA
.
getBooleanNext
(
)
)
;
}

copy array a to array result as bytes
The array a and result must be type boolean

@param result copy to here
@param a copy from here

@throws IllegalArgumentException a and result are not conformable


public static void copyObject(Array result, Array a) throws IllegalArgumentException {
    if (!conformable(a, result))
      throw new IllegalArgumentException("copy arrays are not conformable");

    IndexIterator iterA = a.getIndexIterator();
    IndexIterator iterR = result.getIndexIterator();
    while (iterA.hasNext()) {
      iterR.setObjectNext( iterA.getObjectNext());
    }
  }

public
static
void
copyObject
(
Array
result
,
Array
a
)
throws
IllegalArgumentException
{
if
(
!
conformable
(
a
,
result
)
)
throw
new
IllegalArgumentException
(
"copy arrays are not conformable"
)
;
IndexIterator
iterA
=
a
.
getIndexIterator
(
)
;
IndexIterator
iterR
=
result
.
getIndexIterator
(
)
;
while
(
iterA
.
hasNext
(
)
)
{
iterR
.
setObjectNext
(
iterA
.
getObjectNext
(
)
)
;
}
}

copy array a to array result as an Object
The array a and result must be type object

@param result copy to here
@param a copy from here

@throws IllegalArgumentException a and result are not conformable


public static MAMath.MinMax getMinMax(Array a) {
    IndexIterator iter = a.getIndexIterator();
    double max = -Double.MAX_VALUE;
    double min = Double.MAX_VALUE;
    while (iter.hasNext()) {
      double val = iter.getDoubleNext();
      if (Double.isNaN(val)) continue;
      if (val > max)
        max = val;
      if (val < min)
        min = val;
    }
    return new MinMax(min, max);
  }

public static MAMath . MinMax getMinMax ( Array a ) { IndexIterator iter = a . getIndexIterator ( ) ; double max = - Double . MAX_VALUE ; double min = Double . MAX_VALUE ; while ( iter . hasNext ( ) ) { double val = iter . getDoubleNext ( ) ; if ( Double . isNaN ( val ) ) continue ; if ( val > max ) max = val ; if ( val < min ) min = val ; } return new MinMax ( min , max ) ; }

Find min and max value in this array, getting values as doubles. Skip Double.NaN.

@param a the array.
@return MinMax

Find min and max value in this array getting values as doubles . Skip Double . NaN .


public static void setDouble(Array result, double val) {
    IndexIterator iter = result.getIndexIterator();
    while (iter.hasNext()) {
      iter.setDoubleNext(val);
    }
  }

public static void setDouble ( Array result , double val ) { IndexIterator iter = result . getIndexIterator ( ) ; while ( iter . hasNext ( ) ) { iter . setDoubleNext ( val ) ; } }

Set all the elements of this array to the given double value.
The value is converted to the element type of the array, if needed.

@param result change this Array
@param val set all elements to this value

Set all the elements of this array to the given double value . The value is converted to the element type of the array if needed .


public CatalogBuilder makeCatalogBuilder() {
    CatalogBuilder builder = new CatalogBuilder(this);
    for (Dataset ds : getDatasetsLocal()) {
      builder.addDataset(makeDatasetBuilder(null, ds));
    }
    return builder;
  }

public CatalogBuilder makeCatalogBuilder ( ) { CatalogBuilder builder = new CatalogBuilder ( this ) ; for ( Dataset ds : getDatasetsLocal ( ) ) { builder . addDataset ( makeDatasetBuilder ( null , ds ) ) ; } return builder ; }

turn ConfigCatalog into a mutable CatalogBuilder so we can mutate


static public ProjectionImpl factory(Projection proj) {
    if (proj instanceof ProjectionImpl) {
      return (ProjectionImpl) proj;
    }
    return new ProjectionAdapter(proj);
  }

static public ProjectionImpl factory ( Projection proj ) { if ( proj instanceof ProjectionImpl ) { return ( ProjectionImpl ) proj ; } return new ProjectionAdapter ( proj ) ; }

Create a ProjectionImpl from the projection

@param proj projection
@return a ProjectionImpl representing the projection


public static String unescapeDAPIdentifier(String id) {
    String s;
    try {
      s = unescapeString(id);
    } catch (Exception e) {
      s = null;
    }
    return s;
  }

public static String unescapeDAPIdentifier ( String id ) { String s ; try { s = unescapeString ( id ) ; } catch ( Exception e ) { s = null ; } return s ; }

Define the DEFINITIVE opendap identifier unescape function.

@param id The identifier to unescape.
@return The unescaped identifier.

Define the DEFINITIVE opendap identifier unescape function .


public static String urlDecode(String s) {
    try {
      //s = unescapeString(s, _URIEscape, "", false);
      s = URLDecoder.decode(s, "UTF-8");
    } catch (Exception e) {
      s = null;
    }
    return s;
  }

Define the DEFINITIVE URL unescape function.

@param s The string to unescape.
@return The unescaped expression.

Define the DEFINITIVE URL unescape function .


public static String unescapeURL(String url) {
    String newurl;
    newurl = urlDecode(url);
    return newurl;
  }

public static String unescapeURL ( String url ) { String newurl ; newurl = urlDecode ( url ) ; return newurl ; }

Decode all of the parts of the url including query and fragment

@param url the url to encode


static public String backslashEscape(String x, String reservedChars) {
    if (x == null) {
      return null;
    } else if (reservedChars == null) {
      return x;
    }

    boolean ok = true;
    for (int pos = 0; pos < x.length(); pos++) {
      char c = x.charAt(pos);
      if (reservedChars.indexOf(c) >= 0) {
        ok = false;
        break;
      }
    }
    if (ok) return x;

    // gotta do it
    StringBuilder sb = new StringBuilder(x);
    for (int pos = 0; pos < sb.length(); pos++) {
      char c = sb.charAt(pos);
      if (reservedChars.indexOf(c) < 0) {
        continue;
      }

      sb.setCharAt(pos, '\\');
      pos++;
      sb.insert(pos, c);
      pos++;
    }

    return sb.toString();
  }

static
public
String
backslashEscape
(
String
x
,
String
reservedChars
)
{
if
(
x
==
)
{
return
;
}
else
if
(
reservedChars
==
)
{
return
x
;
}
boolean
ok
=
true
;
for
(
int
pos
=
0
;
pos
<
x
.
length
(
)
;
pos
++
)
{
char
c
=
x
.
charAt
(
pos
)
;
if
(
reservedChars
.
indexOf
(
c
)
>=
0
)
{
ok
=
false
;
break
;
}
}
if
(
ok
)
return
x
;
// gotta do it
StringBuilder
sb
=
new
StringBuilder
(
x
)
;
for
(
int
pos
=
0
;
pos
<
sb
.
length
(
)
;
pos
++
)
{
char
c
=
sb
.
charAt
(
pos
)
;
if
(
reservedChars
.
indexOf
(
c
)
<
0
)
{
continue
;
}
sb
.
setCharAt
(
pos
,
'
'
)
;
pos
++
;
sb
.
insert
(
pos
,
c
)
;
pos
++
;
}
return
sb
.
toString
(
)
;
}

backslash escape a string

@param x             escape this; may be null
@param reservedChars these chars get a backslash in front of them
@return escaped string


static public String backslashUnescape(String x) {
    if (!x.contains("\\")) return x;

    // gotta do it
    StringBuilder sb = new StringBuilder(x.length());
    for (int pos = 0; pos < x.length(); pos++) {
      char c = x.charAt(pos);
      if (c == '\\') {
        c = x.charAt(++pos); // skip backslash, get next cha
      }
      sb.append(c);
    }

    return sb.toString();
  }

static
public
String
backslashUnescape
(
String
x
)
{
if
(
!
x
.
contains
(
"\\"
)
)
return
x
;
// gotta do it
StringBuilder
sb
=
new
StringBuilder
(
x
.
length
(
)
)
;
for
(
int
pos
=
0
;
pos
<
x
.
length
(
)
;
pos
++
)
{
char
c
=
x
.
charAt
(
pos
)
;
if
(
c
==
'
'
)
{
c
=
x
.
charAt
(
++
pos
)
;
// skip backslash, get next cha
}
sb
.
append
(
c
)
;
}
return
sb
.
toString
(
)
;
}

backslash unescape a string

@param x unescape this
@return string with \c -> c


public static List<String> tokenizeEscapedName(String escapedName) {
    List<String> result = new ArrayList<>();
    int pos = 0;
    int start = 0;
    while (true) {
      pos = escapedName.indexOf(sep, pos + 1);
      if (pos <= 0) break;
      if ((pos > 0) && escapedName.charAt(pos - 1) != '\\') {
        result.add(escapedName.substring(start, pos));
        start = pos + 1;
      }
    }
    result.add(escapedName.substring(start, escapedName.length())); // remaining
    return result;
  }

public
static
List
<
String
>
tokenizeEscapedName
(
String
escapedName
)
{
List
<
String
>
result
=
new
ArrayList
<>
(
)
;
int
pos
=
0
;
int
start
=
0
;
while
(
true
)
{
pos
=
escapedName
.
indexOf
(
sep
,
pos
+
1
)
;
if
(
pos
<=
0
)
break
;
if
(
(
pos
>
0
)
&&
escapedName
.
charAt
(
pos
1
)
!=
'
'
)
{
result
.
add
(
escapedName
.
substring
(
start
,
pos
)
)
;
start
=
pos
+
1
;
}
}
result
.
add
(
escapedName
.
substring
(
start
,
escapedName
.
length
(
)
)
)
;
// remaining
return
result
;
}

Tokenize an escaped name using "." as delimiter, skipping "\."

@param escapedName an escaped name
@return list of tokens

Tokenize an escaped name using . as delimiter skipping \ .


public static int indexOf(String escapedName, char c) {
    int pos = 0;
    while (true) {
      pos = escapedName.indexOf(c, pos + 1);
      if (pos <= 0) return pos;
      if ((pos > 0) && escapedName.charAt(pos - 1) != '\\') return pos;
    }
  }

public static int indexOf ( String escapedName , char c ) { int pos = 0 ; while ( true ) { pos = escapedName . indexOf ( c , pos + 1 ) ; if ( pos <= 0 ) return pos ; if ( ( pos > 0 ) && escapedName . charAt ( pos - 1 ) != ' ' ) return pos ; } }

Find first occurence of char c in escapedName, excluding escaped c.

@param escapedName search in this string
@param c           for this char but not \\cha
@return pos in string, or -1

Find first occurence of char c in escapedName excluding escaped c .


public static String backslashToDAP(String bs) {
    StringBuilder buf = new StringBuilder();
    int len = bs.length();
    for (int i = 0; i < len; i++) {
      char c = bs.charAt(i);
      if (i < (len - 1) && c == '\\') {
        c = bs.charAt(++i);
      }
      if (_allowableInDAP.indexOf(c) < 0) {
        buf.append(_URIEscape);
        // convert the char to hex
        String ashex = Integer.toHexString((int) c);
        if (ashex.length() < 2) buf.append('0');
        buf.append(ashex);
      } else
        buf.append(c);
    }
    return buf.toString();
  }

public
static
String
backslashToDAP
(
String
bs
)
{
StringBuilder
buf
=
new
StringBuilder
(
)
;
int
len
=
bs
.
length
(
)
;
for
(
int
i
=
0
;
i
<
len
;
i
++
)
{
char
c
=
bs
.
charAt
(
i
)
;
if
(
i
<
(
len
1
)
&&
c
==
'
'
)
{
c
=
bs
.
charAt
(
++
i
)
;
}
if
(
_allowableInDAP
.
indexOf
(
c
)
<
0
)
{
buf
.
append
(
_URIEscape
)
;
// convert the char to hex
String
ashex
=
Integer
.
toHexString
(
(
int
)
c
)
;
if
(
ashex
.
length
(
)
<
2
)
buf
.
append
(
'
'
)
;
buf
.
append
(
ashex
)
;
}
else
buf
.
append
(
c
)
;
}
return
buf
.
toString
(
)
;
}

Given a backslash escaped name,
convert to a DAP escaped name

@param bs the string to DAP encode; may have backslash escapes
@return escaped string

Given a backslash escaped name convert to a DAP escaped name