Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 1998-2013 University Corporation for Atmospheric Research/Unidata
*
* Portions of this software were developed by the Unidata Program at the
* University Corporation for Atmospheric Research.
*
* Access and use of this software shall impose the following obligations
* and understandings on the user. The user is granted the right, without
* any fee or cost, to use, copy, modify, alter, enhance and distribute
* this software, and any derivative works thereof, and its supporting
* documentation for any purpose whatsoever, provided that this entire
* notice appears in all copies of the software, derivative works and
* supporting documentation. Further, UCAR requests that the user credit
* UCAR/Unidata in any publications that result from the use of this
* software or in any product that includes this software. The names UCAR
* and/or Unidata, however, may not be used in any advertising or publicity
* to endorse or promote any products or commercial entity unless specific
* written permission is obtained from UCAR/Unidata. The user also
* understands that UCAR/Unidata is not obligated to provide the user with
* any support, consulting, training or assistance of any kind with regard
* to the use, operation and performance of this software nor to provide
* the user with any updates, revisions, new versions or "bug fixes."
*
* THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package ucar.nc2.jni.netcdf;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import thredds.catalog.DataFormatType;
import ucar.ma2.*;
import ucar.nc2.*;
import ucar.nc2.constants.CDM;
import ucar.nc2.iosp.AbstractIOServiceProvider;
import ucar.nc2.iosp.IOServiceProviderWriter;
import ucar.nc2.iosp.IospHelper;
import ucar.nc2.iosp.hdf4.HdfEos;
import ucar.nc2.iosp.hdf5.H5header;
import ucar.nc2.util.CancelTask;
import ucar.nc2.util.DebugFlags;
import ucar.nc2.write.Nc4Chunking;
import ucar.nc2.write.Nc4ChunkingDefault;
import ucar.unidata.io.RandomAccessFile;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.util.*;
import static ucar.nc2.jni.netcdf.Nc4prototypes.*;
/**
* IOSP for reading netcdf files through jni interface to netcdf4 library
*
* @author caron
* @see "http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-c.html"
* @see "http://earthdata.nasa.gov/sites/default/files/field/document/ESDS-RFC-022v1.pdf"
* @see "http://www.unidata.ucar.edu/software/netcdf/docs/faq.html#fv15"
* hdf5 features not supported
* @see "http://www.unidata.ucar.edu/software/netcdf/win_netcdf/"
* @since Oct 30, 2008
*/
public class Nc4Iosp extends AbstractIOServiceProvider implements IOServiceProviderWriter {
static public final boolean DEBUG = false;
static private org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Nc4Iosp.class);
static private org.slf4j.Logger startupLog = org.slf4j.LoggerFactory.getLogger("serverStartup");
static private Nc4prototypes nc4;
static public final String JNA_PATH = "jna.library.path";
static public final String JNA_PATH_ENV = "JNA_PATH"; // environment var
static protected String DEFAULTNETCDF4LIBNAME = "netcdf";
//static protected String netcdf4libname = DEFAULTNETCDF4LIBNAME;
static String[] DEFAULTNETCDF4PATH = new String[]{
"/opt/netcdf4/lib",
"/home/dmh/opt/netcdf4/lib", //temporary
"c:/opt/netcdf", // Windows
"/usr/jna_lib/",
};
static private String jnaPath = null;
static private String libName = DEFAULTNETCDF4LIBNAME;
static private final boolean debug = false,
debugCompound = false,
debugCompoundAtt = false,
debugDim = false,
debugUserTypes = false,
debugLoad = true,
debugWrite = false;
/**
* Use the default path to try to set jna.library.path
*
* @return true if we set jna.library.path
*/
static private String defaultNetcdf4Library() {
StringBuilder pathlist = new StringBuilder();
for (String path : DEFAULTNETCDF4PATH) {
File f = new File(path);
if (f.exists() && f.canRead()) {
if(pathlist.length() > 0)
pathlist.append(File.pathSeparator);
pathlist.append(path);
break;
}
}
return pathlist.length() == 0 ? null : pathlist.toString();
}
/**
* set the path and name of the netcdf c library.
* must be called before load() is called.
*
* @param jna_path path to shared libraries
* @param lib_name library name
*/
static public void setLibraryAndPath(String jna_path, String lib_name) {
lib_name = nullify(lib_name);
if (lib_name == null) {
lib_name = DEFAULTNETCDF4LIBNAME;
}
jna_path = nullify(jna_path);
if (jna_path == null) {
jna_path = nullify(System.getProperty(JNA_PATH)); // First, try system property (-D flag).
}
if (jna_path == null) {
jna_path = nullify(System.getenv(JNA_PATH_ENV)); // Next, try environment variable.
}
if (jna_path == null) {
jna_path = defaultNetcdf4Library(); // Last, try some default paths.
}
if (jna_path != null) {
System.setProperty(JNA_PATH, jna_path);
}
libName = lib_name;
jnaPath = jna_path;
}
static private Nc4prototypes load() {
if (nc4 == null) {
if (jnaPath == null) {
setLibraryAndPath(null, null);
}
try {
// jna_path may still be null (the user didn't specify a "jna.library.path"), but try to load anyway;
// the necessary libs may be on the system PATH.
nc4 = (Nc4prototypes) Native.loadLibrary(libName, Nc4prototypes.class);
String message = String.format("NetCDF-4 C library loaded (jna_path='%s', libname='%s').", jnaPath, libName);
startupLog.info(message);
if (debugLoad) {
System.out.println(message);
System.out.printf("Netcdf nc_inq_libvers='%s' isProtected=%s%n", nc4.nc_inq_libvers(), Native.isProtected());
}
} catch (Throwable t) {
String message = String.format("NetCDF-4 C library not present (jna_path='%s', libname='%s').", jnaPath, libName);
startupLog.warn(message);
if (debugLoad) {
System.out.println(message);
}
}
}
return nc4;
}
/**
* Test if the netcdf C library is present and loaded
*
* @return true if present
*/
public static boolean isClibraryPresent() {
return load() != null;
}
/**
* Convert a zero-length string to null
*
* @param s the string to check for length
* @return null if s.length() == 0, s otherwise
*/
static protected String nullify(String s) {
if (s != null && s.length() == 0) s = null;
return s;
}
static private boolean skipEos = false;
static public void setDebugFlags(DebugFlags flags) {
skipEos = flags.isSet("HdfEos/turnOff");
}
//////////////////////////////////////////////////
// Instance Variables
private NetcdfFileWriter.Version version = null; // can use c library to create these different version files
private NetcdfFile ncfile = null;
private boolean fill = true;
private int ncid = -1; // file id
private int format = 0; // from nc_inq_format
private boolean isClosed = false;
private Map userTypes = new HashMap<>(); // hash by typeid
private Map groupHash = new HashMap<>(); // group -> nc4 grpid
private Nc4Chunking chunker = new Nc4ChunkingDefault();
private boolean isEos = false;
//////////////////////////////////////////////////
// Constructor(s)
public Nc4Iosp() {
this(NetcdfFileWriter.Version.netcdf4); // ensure the version always has a value
}
public Nc4Iosp(NetcdfFileWriter.Version version) {
this.version = version;
}
// called by reflection from NetcdfFileWriter
public void setChunker(Nc4Chunking chunker) {
if (chunker != null)
this.chunker = chunker;
}
public boolean isValidFile(RandomAccessFile raf) throws IOException {
boolean match = false;
if (raf.getLocation().endsWith(".nc")) { // LOOK not a very good criteria
long savepos = raf.getFilePointer();
raf.seek(1);
byte[] hdr = new byte[3];
raf.readFully(hdr);
String shdr = new String(hdr, "US-ASCII");
if ("HDF".equals(shdr)) match = true;
raf.seek(savepos);
}
return match;
}
public String getFileTypeId() {
if (isEos) return "HDF5-EOS";
return version.isNetdf4format() ? DataFormatType.NETCDF4.toString() : DataFormatType.NETCDF.toString();
}
public String getFileTypeDescription() {
return "Netcdf/JNI: " + version;
}
public void close() throws IOException {
if (isClosed) return;
if (ncid < 0) return;
int ret = nc4.nc_close(ncid);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
isClosed = true;
// System.out.printf("%s closed%n", ncfile.getLocation());
}
public void open(RandomAccessFile raf, NetcdfFile ncfile, CancelTask cancelTask) throws IOException {
_open(raf, ncfile, true);
}
public void openForWriting(ucar.unidata.io.RandomAccessFile raf, ucar.nc2.NetcdfFile ncfile, ucar.nc2.util.CancelTask cancelTask) throws IOException {
_open(raf, ncfile, false);
}
private void _open(RandomAccessFile raf, NetcdfFile ncfile, boolean readOnly) throws IOException {
if (!isClibraryPresent()) {
throw new UnsupportedOperationException("Couldn't load NetCDF C library (see log for details).");
}
if(raf != null)
raf.close(); // not used
this.ncfile = ncfile;
// open
if (debug) System.out.println("open " + ncfile.getLocation());
IntByReference ncidp = new IntByReference();
int ret = nc4.nc_open(ncfile.getLocation(), readOnly ? NC_NOWRITE : NC_WRITE, ncidp);
if (ret != 0) throw new IOException(ret + ": " + nc4.nc_strerror(ret));
ncid = ncidp.getValue();
// format
IntByReference formatp = new IntByReference();
ret = nc4.nc_inq_format(ncid, formatp);
if (ret != 0) throw new IOException(ret + ": " + nc4.nc_strerror(ret));
format = formatp.getValue();
if (debug) System.out.printf("open %s id=%d format=%d %n", ncfile.getLocation(), ncid, format);
// read root group
makeGroup(new Group4(ncid, ncfile.getRootGroup(), null));
// check if its an HDF5-EOS file
Group eosInfo = ncfile.getRootGroup().findGroup(HdfEos.HDF5_GROUP);
if (eosInfo != null && !skipEos) {
isEos = HdfEos.amendFromODL(ncfile, eosInfo);
}
ncfile.finish();
}
private void makeGroup(Group4 g4) throws IOException {
groupHash.put(g4.g, g4.grpid);
makeDimensions(g4);
makeUserTypes(g4.grpid, g4.g);
// group attributes
IntByReference ngattsp = new IntByReference();
int ret = nc4.nc_inq_natts(g4.grpid, ngattsp);
if (ret != 0) throw new IOException(ret + ": " + nc4.nc_strerror(ret));
List gatts = makeAttributes(g4.grpid, Nc4prototypes.NC_GLOBAL, ngattsp.getValue(), null);
for (Attribute att : gatts) {
ncfile.addAttribute(g4.g, att);
if (debug) System.out.printf(" add Global Attribute %s %n", att);
}
makeVariables(g4);
if (format == Nc4prototypes.NC_FORMAT_NETCDF4) {
// read subordinate groups
IntByReference numgrps = new IntByReference();
ret = nc4.nc_inq_grps(g4.grpid, numgrps, Pointer.NULL);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
int[] group_ids = new int[numgrps.getValue()];
ret = nc4.nc_inq_grps(g4.grpid, numgrps, group_ids);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
for (int group_id : group_ids) {
byte[] name = new byte[Nc4prototypes.NC_MAX_NAME + 1];
ret = nc4.nc_inq_grpname(group_id, name);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
Group child = new Group(ncfile, g4.g, makeString(name));
g4.g.addGroup(child);
makeGroup(new Group4(group_id, child, g4));
}
}
}
private void makeDimensions(Group4 g4) throws IOException {
IntByReference ndimsp = new IntByReference();
int ret = nc4.nc_inq_ndims(g4.grpid, ndimsp);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
int[] dimids = new int[ndimsp.getValue()];
ret = nc4.nc_inq_dimids(g4.grpid, ndimsp, dimids, 0);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
IntByReference nunlimdimsp = new IntByReference();
int[] unlimdimids = new int[Nc4prototypes.NC_MAX_DIMS];
ret = nc4.nc_inq_unlimdims(g4.grpid, nunlimdimsp, unlimdimids);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
int ndims = ndimsp.getValue();
for (int i = 0; i < ndims; i++) {
byte[] name = new byte[Nc4prototypes.NC_MAX_NAME + 1];
SizeTByReference lenp = new SizeTByReference();
ret = nc4.nc_inq_dim(g4.grpid, dimids[i], name, lenp);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
String dname = makeString(name);
boolean isUnlimited = containsInt(nunlimdimsp.getValue(), unlimdimids, i);
Dimension dim = new Dimension(dname, lenp.getValue().intValue(), true, isUnlimited, false);
ncfile.addDimension(g4.g, dim);
if (debug) System.out.printf(" add Dimension %s (%d) %n", dim, dimids[i]);
}
}
private boolean containsInt(int n, int[] have, int want) {
for (int i = 0; i < n; i++) {
if (have[i] == want) return true;
}
return false;
}
private void updateDimensions(Group g) throws IOException {
int grpid = groupHash.get(g);
IntByReference nunlimdimsp = new IntByReference();
int[] unlimdimids = new int[Nc4prototypes.NC_MAX_DIMS];
int ret = nc4.nc_inq_unlimdims(grpid, nunlimdimsp, unlimdimids);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
int ndims = nunlimdimsp.getValue();
for (int i = 0; i < ndims; i++) {
byte[] name = new byte[Nc4prototypes.NC_MAX_NAME + 1];
SizeTByReference lenp = new SizeTByReference();
ret = nc4.nc_inq_dim(grpid, unlimdimids[i], name, lenp);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
String dname = makeString(name);
Dimension d = g.findDimension(dname);
if (d == null)
throw new IllegalStateException("Cant find dimension " + dname);
if (!d.isUnlimited())
throw new IllegalStateException("dimension " + dname + " should be unlimited");
int len = lenp.getValue().intValue();
if (len != d.getLength()) {
d.setLength(len);
// must update all variables that use this dimension
for (Variable var : g.getVariables()) {
if (contains(var.getDimensions(), d)) {
var.resetShape();
var.invalidateCache();
}
}
}
}
// recurse
for (Group child : g.getGroups())
updateDimensions(child);
}
// must check by name, not object equality
private boolean contains(List dims, Dimension want) {
for (Dimension have : dims) {
if (have.getShortName().equals(want.getShortName())) return true;
}
return false;
}
private String makeString(byte[] b) {
// null terminates
int count = 0;
while (count < b.length) {
if (b[count] == 0) break;
count++; // dont include the terminating 0
}
// copy if its small
if (count < b.length / 2) {
byte[] bb = new byte[count];
System.arraycopy(b, 0, bb, 0, count);
b = bb;
}
return new String(b, 0, count, CDM.utf8Charset); // all strings are considered to be UTF-8 unicode.
}
// follow what happens in the Java side
private String makeAttString(byte[] b) throws IOException {
// null terminates
int count = 0;
while (count < b.length) {
if (b[count] == 0) break;
count++; // dont include the terminating 0
}
return new String(b, 0, count, CDM.utf8Charset); // all strings are considered to be UTF-8 unicode.
/*
char[] carray = new char[count];
for (int i=0; i makeAttributes(int grpid, int varid, int natts, Variable v) throws IOException {
List result = new ArrayList<>(natts);
for (int attnum = 0; attnum < natts; attnum++) {
byte[] name = new byte[Nc4prototypes.NC_MAX_NAME + 1];
int ret = nc4.nc_inq_attname(grpid, varid, attnum, name);
if (ret != 0)
throw new IOException(nc4.nc_strerror(ret) + " varid=" + varid + " attnum=" + attnum);
String attname = makeString(name);
IntByReference xtypep = new IntByReference();
ret = nc4.nc_inq_atttype(grpid, varid, attname, xtypep);
if (ret != 0)
throw new IOException(nc4.nc_strerror(ret) + " varid=" + varid + "attnum=" + attnum);
/* xtypep : Pointer to location for returned attribute type,
one of the set of predefined netCDF external data types.
The type of this parameter, nc_type, is defined in the netCDF
header file. The valid netCDF external data types are
NC_BYTE, NC_CHAR, NC_SHORT, NC_INT, NC_FLOAT, and NC_DOUBLE.
If this parameter is given as '0' (a null pointer), no type
will be returned so no variable to hold the type needs to be declared.
*/
int type = xtypep.getValue();
SizeTByReference lenp = new SizeTByReference();
ret = nc4.nc_inq_attlen(grpid, varid, attname, lenp);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
int len = lenp.getValue().intValue();
// deal with empty attributes
if (len == 0) {
Attribute att;
switch (type) {
case Nc4prototypes.NC_BYTE:
case Nc4prototypes.NC_UBYTE:
att = new Attribute(attname, DataType.BYTE, type == Nc4prototypes.NC_UBYTE);
break;
case Nc4prototypes.NC_CHAR: // a zero length char is considered to be an empty string
att = new Attribute(attname, "");
break;
case Nc4prototypes.NC_DOUBLE:
att = new Attribute(attname, DataType.DOUBLE, false);
break;
case Nc4prototypes.NC_FLOAT:
att = new Attribute(attname, DataType.FLOAT, false);
break;
case Nc4prototypes.NC_INT:
case Nc4prototypes.NC_UINT:
att = new Attribute(attname, DataType.INT, type == Nc4prototypes.NC_UINT);
break;
case Nc4prototypes.NC_UINT64:
case Nc4prototypes.NC_INT64:
att = new Attribute(attname, DataType.LONG, type == Nc4prototypes.NC_UINT64);
break;
case Nc4prototypes.NC_USHORT:
case Nc4prototypes.NC_SHORT:
att = new Attribute(attname, DataType.SHORT, type == Nc4prototypes.NC_USHORT);
break;
case Nc4prototypes.NC_STRING:
att = new Attribute(attname, DataType.STRING, false);
break;
default:
log.warn("Unsupported attribute data type == " + type);
continue;
}
result.add(att);
continue; // avoid reading the values since there are none.
}
// read the att values
Array values = null;
switch (type) {
case Nc4prototypes.NC_UBYTE:
byte[] valbu = new byte[len];
ret = nc4.nc_get_att_uchar(grpid, varid, attname, valbu);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
values = Array.factory(DataType.BYTE.getPrimitiveClassType(), new int[]{len}, valbu);
break;
case Nc4prototypes.NC_BYTE:
byte[] valb = new byte[len];
ret = nc4.nc_get_att_schar(grpid, varid, attname, valb);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
values = Array.factory(DataType.BYTE.getPrimitiveClassType(), new int[]{len}, valb);
break;
case Nc4prototypes.NC_CHAR:
byte[] text = new byte[len];
ret = nc4.nc_get_att_text(grpid, varid, attname, text);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
Attribute att = new Attribute(attname, makeAttString(text));
result.add(att);
break;
case Nc4prototypes.NC_DOUBLE:
double[] vald = new double[len];
ret = nc4.nc_get_att_double(grpid, varid, attname, vald);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
values = Array.factory(DataType.DOUBLE.getPrimitiveClassType(), new int[]{len}, vald);
break;
case Nc4prototypes.NC_FLOAT:
float[] valf = new float[len];
ret = nc4.nc_get_att_float(grpid, varid, attname, valf);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
values = Array.factory(DataType.FLOAT.getPrimitiveClassType(), new int[]{len}, valf);
break;
case Nc4prototypes.NC_UINT:
int[] valiu = new int[len];
ret = nc4.nc_get_att_uint(grpid, varid, attname, valiu);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
values = Array.factory(DataType.INT.getPrimitiveClassType(), new int[]{len}, valiu);
break;
case Nc4prototypes.NC_INT:
int[] vali = new int[len];
ret = nc4.nc_get_att_int(grpid, varid, attname, vali);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
values = Array.factory(DataType.INT.getPrimitiveClassType(), new int[]{len}, vali);
break;
case Nc4prototypes.NC_UINT64:
long[] vallu = new long[len];
ret = nc4.nc_get_att_ulonglong(grpid, varid, attname, vallu);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
values = Array.factory(DataType.LONG.getPrimitiveClassType(), new int[]{len}, vallu);
break;
case Nc4prototypes.NC_INT64:
long[] vall = new long[len];
ret = nc4.nc_get_att_longlong(grpid, varid, attname, vall);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
values = Array.factory(DataType.LONG.getPrimitiveClassType(), new int[]{len}, vall);
break;
case Nc4prototypes.NC_USHORT:
short[] valsu = new short[len];
ret = nc4.nc_get_att_ushort(grpid, varid, attname, valsu);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
values = Array.factory(DataType.SHORT.getPrimitiveClassType(), new int[]{len}, valsu);
break;
case Nc4prototypes.NC_SHORT:
short[] vals = new short[len];
ret = nc4.nc_get_att_short(grpid, varid, attname, vals);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
values = Array.factory(DataType.SHORT.getPrimitiveClassType(), new int[]{len}, vals);
break;
case Nc4prototypes.NC_STRING:
if (len > 1)
System.out.println("HEY string len > 1");
String[] valss = new String[len];
ret = nc4.nc_get_att_string(grpid, varid, attname, valss);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
values = Array.factory(String.class, new int[]{len}, valss);
break;
default:
UserType userType = userTypes.get(type);
if (userType == null) {
log.warn("Unsupported attribute data type == " + type);
continue;
} else if (userType.typeClass == Nc4prototypes.NC_ENUM) {
result.add(readEnumAttValues(grpid, varid, attname, len, userType));
continue;
} else if (userType.typeClass == Nc4prototypes.NC_OPAQUE) {
result.add(readOpaqueAttValues(grpid, varid, attname, len, userType));
continue;
} else if (userType.typeClass == Nc4prototypes.NC_VLEN) {
values = readVlenAttValues(grpid, varid, attname, len, userType);
} else if (userType.typeClass == Nc4prototypes.NC_COMPOUND) {
readCompoundAttValues(grpid, varid, attname, len, userType, result, v);
continue;
} else {
log.warn("Unsupported attribute data type == " + userType);
continue;
}
}
if (values != null) {
Attribute att = new Attribute(attname, values);
result.add(att);
}
}
return result;
}
private Array readVlenAttValues(int grpid, int varid, String attname, int len, UserType userType) throws IOException {
Nc4prototypes.Vlen_t[] vlen = new Nc4prototypes.Vlen_t[len];
int ret = nc4.nc_get_att(grpid, varid, attname, vlen); // vlen
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
int count = 0;
for (int i = 0; i < len; i++)
count += vlen[i].len;
switch (userType.baseTypeid) {
case Nc4prototypes.NC_INT:
Array intArray = Array.factory(DataType.INT, new int[]{count});
IndexIterator iter = intArray.getIndexIterator();
for (int i = 0; i < len; i++) {
//System.out.print(" len=" + vlen[i].len + "; p= " + vlen[i].p + ";");
//Coverity[FB.UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD]
int[] ba = vlen[i].p.getIntArray(0, vlen[i].len);
for (int aBa : ba) {
//System.out.print(" " + ba[j]);
iter.setIntNext(aBa);
}
//System.out.println();
}
return intArray;
case Nc4prototypes.NC_FLOAT:
Array fArray = Array.factory(DataType.FLOAT, new int[]{count});
iter = fArray.getIndexIterator();
for (int i = 0; i < len; i++) {
//Coverity[FB.NP_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD]
float[] ba = vlen[i].p.getFloatArray(0, vlen[i].len);
for (float aBa : ba) iter.setFloatNext(aBa);
}
return fArray;
}
return null;
}
private Attribute readEnumAttValues(int grpid, int varid, String attname, int len, UserType userType) throws IOException {
int ret;
DataType dtype = convertDataType(userType.baseTypeid).dt;
int elemSize = dtype.getSize();
byte[] bbuff = new byte[len * elemSize];
ret = nc4.nc_get_att(grpid, varid, attname, bbuff);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
ByteBuffer bb = ByteBuffer.wrap(bbuff);
Array data = convertByteBuffer(bb, userType.baseTypeid, new int[]{len});
IndexIterator ii = data.getIndexIterator();
if (len == 1) {
String val = userType.e.lookupEnumString(ii.getIntNext());
return new Attribute(attname, val);
} else {
ArrayObject.D1 attArray = (ArrayObject.D1) Array.factory(DataType.STRING, new int[]{len});
for (int i = 0; i < len; i++) {
int val = ii.getIntNext();
String vals = userType.e.lookupEnumString(val);
if (vals == null)
throw new IOException("Illegal enum val " + val + " for attribute " + attname);
attArray.set(i, vals);
}
return new Attribute(attname, attArray);
}
}
private Array convertByteBuffer(ByteBuffer bb, int baseType, int shape[]) throws IOException {
switch (baseType) {
case Nc4prototypes.NC_BYTE:
case Nc4prototypes.NC_UBYTE:
Array sArray = Array.factory(DataType.BYTE, shape, bb.array());
return (baseType == Nc4prototypes.NC_BYTE) ? sArray : MAMath.convertUnsigned(sArray);
case Nc4prototypes.NC_SHORT:
case Nc4prototypes.NC_USHORT:
ShortBuffer sb = bb.asShortBuffer();
sArray = Array.factory(DataType.SHORT, shape, sb.array());
return (baseType == Nc4prototypes.NC_SHORT) ? sArray : MAMath.convertUnsigned(sArray);
case Nc4prototypes.NC_INT:
case Nc4prototypes.NC_UINT:
IntBuffer ib = bb.asIntBuffer();
sArray = Array.factory(DataType.INT, shape, ib.array());
return (baseType == Nc4prototypes.NC_INT) ? sArray : MAMath.convertUnsigned(sArray);
}
throw new IllegalArgumentException("Illegal type="+baseType);
}
private Attribute readOpaqueAttValues(int grpid, int varid, String attname, int len, UserType userType) throws IOException {
int total = len * userType.size;
byte[] bb = new byte[total];
int ret = nc4.nc_get_att(grpid, varid, attname, bb);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
return new Attribute(attname, Array.factory(DataType.BYTE, new int[]{total}, bb));
}
private void readCompoundAttValues(int grpid, int varid, String attname, int len, UserType userType, List result, Variable v)
throws IOException {
int buffSize = len * userType.size;
byte[] bb = new byte[buffSize];
int ret = nc4.nc_get_att(grpid, varid, attname, bb);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
ByteBuffer bbuff = ByteBuffer.wrap(bb);
decodeCompoundData(len, userType, bbuff);
// if its a Structure, distribute to matching fields
if ((v != null) && (v instanceof Structure)) {
Structure s = (Structure) v;
for (Field fld : userType.flds) {
Variable mv = s.findVariable(fld.name);
if (mv != null)
mv.addAttribute(new Attribute(attname, fld.data));
else
result.add(new Attribute(attname + "." + fld.name, fld.data));
}
} else {
for (Field fld : userType.flds)
result.add(new Attribute(attname + "." + fld.name, fld.data));
}
}
// LOOK: placing results in the fld of the userType - ok for production ??
private void decodeCompoundData(int len, UserType userType, ByteBuffer bbuff) throws IOException {
bbuff.order(ByteOrder.LITTLE_ENDIAN);
for (Field fld : userType.flds) {
ConvertedType ct = convertDataType(fld.fldtypeid);
if (fld.fldtypeid == Nc4prototypes.NC_CHAR) {
fld.data = Array.factory(DataType.STRING, new int[]{len}); // LOOK ??
} else if (ct.isVlen) {
fld.data = new ArrayObject(ct.dt.getPrimitiveClassType(), new int[]{len});
// fld.data = Array.factory( Object.class, new int[] { len}); // object array
} else {
fld.data = Array.factory(ct.dt, new int[]{len});
}
if (ct.isUnsigned) fld.data.setUnsigned(true);
}
for (int i = 0; i < len; i++) {
int record_start = i * userType.size;
for (Field fld : userType.flds) {
int pos = record_start + fld.offset;
switch (fld.fldtypeid) {
case Nc4prototypes.NC_CHAR:
// copy bytes out of buffer, make into a String object
int blen = 1;
if (fld.dims != null) {
Section s = new Section(fld.dims);
blen = (int) s.computeSize();
}
byte[] dst = new byte[blen];
bbuff.get(dst, 0, blen);
String cval = makeAttString(dst);
fld.data.setObject(i, cval);
if (debugCompoundAtt) System.out.println("result= " + cval);
continue;
case Nc4prototypes.NC_UBYTE:
case Nc4prototypes.NC_BYTE:
byte bval = bbuff.get(pos);
if (debugCompoundAtt) System.out.println("bval= " + bval);
fld.data.setByte(i, bval);
continue;
case Nc4prototypes.NC_USHORT:
case Nc4prototypes.NC_SHORT:
short sval = bbuff.getShort(pos);
if (debugCompoundAtt) System.out.println("sval= " + sval);
fld.data.setShort(i, sval);
continue;
case Nc4prototypes.NC_UINT:
case Nc4prototypes.NC_INT:
int ival = bbuff.getInt(pos);
if (debugCompoundAtt) System.out.println("ival= " + ival);
fld.data.setInt(i, ival);
continue;
case Nc4prototypes.NC_UINT64:
case Nc4prototypes.NC_INT64:
long lval = bbuff.getLong(pos);
if (debugCompoundAtt) System.out.println("lval= " + lval);
fld.data.setLong(i, lval);
continue;
case Nc4prototypes.NC_FLOAT:
float fval = bbuff.getFloat(pos);
if (debugCompoundAtt) System.out.println("fval= " + fval);
fld.data.setFloat(i, fval);
continue;
case Nc4prototypes.NC_DOUBLE:
double dval = bbuff.getDouble(pos);
if (debugCompoundAtt) System.out.println("dval= " + dval);
fld.data.setDouble(i, dval);
continue;
case Nc4prototypes.NC_STRING:
lval = getNativeAddr(pos,bbuff);
Pointer p = new Pointer(lval);
String strval = p.getString(0, CDM.UTF8);
fld.data.setObject(i, strval);
if (debugCompoundAtt) System.out.println("result= " + strval);
continue;
default:
UserType subUserType = userTypes.get(fld.fldtypeid);
if (subUserType == null) {
throw new IOException("Unknown compound user type == " + fld);
} else if (subUserType.typeClass == Nc4prototypes.NC_ENUM) {
// WTF ?
} else if (subUserType.typeClass == Nc4prototypes.NC_VLEN) {
decodeVlenField(fld, subUserType, pos, i, bbuff);
break;
} else if (subUserType.typeClass == Nc4prototypes.NC_OPAQUE) {
//return readOpaque(grpid, varid, len, userType.size);
} else if (subUserType.typeClass == Nc4prototypes.NC_COMPOUND) {
//return readCompound(grpid, varid, len, userType);
}
log.warn("UNSUPPORTED compound fld.fldtypeid= " + fld.fldtypeid);
continue;
} // switch on fld type
} // loop over fields
} // loop over len
}
/////////////////////////////////////////////////////////////////////////////
private void makeVariables(Group4 g4) throws IOException {
IntByReference nvarsp = new IntByReference();
int ret = nc4.nc_inq_nvars(g4.grpid, nvarsp);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
int nvars = nvarsp.getValue();
if (debug) System.out.printf(" nvars= %d %n", nvars);
int[] varids = new int[nvars];
ret = nc4.nc_inq_varids(g4.grpid, nvarsp, varids);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
for (int i = 0; i < varids.length; i++) {
int varno = varids[i];
if (varno != i) log.error("HEY varno=%d i=%d%n", varno, i);
byte[] name = new byte[Nc4prototypes.NC_MAX_NAME + 1];
IntByReference xtypep = new IntByReference();
IntByReference ndimsp = new IntByReference();
int[] dimids = new int[Nc4prototypes.NC_MAX_DIMS];
IntByReference nattsp = new IntByReference();
ret = nc4.nc_inq_var(g4.grpid, varno, name, xtypep, ndimsp, dimids, nattsp);
if (ret != 0)
throw new IOException(nc4.nc_strerror(ret));
// figure out the datatype
int typeid = xtypep.getValue();
//DataType dtype = convertDataType(typeid).dt;
String vname = makeString(name);
Vinfo vinfo = new Vinfo(g4, varno, typeid);
// figure out the dimensions
String dimList = makeDimList(g4.grpid, ndimsp.getValue(), dimids);
UserType utype = userTypes.get(typeid);
if (utype != null) {
//Coverity[FB.URF_UNREAD_FIELD]
vinfo.utype = utype;
if (utype.typeClass == Nc4prototypes.NC_VLEN) // LOOK ??
dimList = dimList + " *";
}
Variable v = makeVariable(g4.g, null, vname, typeid, dimList);
/* if(dtype != DataType.STRUCTURE) {
v = new Variable(ncfile, g, null, vname, dtype, dimList);
} else if(utype != null) {
Structure s = new Structure(ncfile, g, null, vname);
s.setDimensions(dimList);
v = s;
if(utype.flds == null)
utype.readFields();
for(Field f : utype.flds) {
s.addMemberVariable(f.makeMemberVariable(g, s));
}
} else {
throw new IllegalStateException("Dunno what to with " + dtype);
} */
// create the Variable
ncfile.addVariable(g4.g, v);
v.setSPobject(vinfo);
if (isUnsigned(typeid))
v.addAttribute(new Attribute(CDM.UNSIGNED, "true"));
// read Variable attributes
List atts = makeAttributes(g4.grpid, varno, nattsp.getValue(), v);
for (Attribute att : atts) {
v.addAttribute(att);
}
if (debug) System.out.printf(" added Variable %s %n", v);
}
}
private Variable makeVariable(Group g, Structure parent, String vname, int typeid, String dimList) throws IOException {
//if (typeid == Nc4prototypes.NC_STRING)
// System.out.println("HEY");
ConvertedType cvttype = convertDataType(typeid);
DataType dtype = cvttype.dt;
UserType utype = userTypes.get(typeid);
Variable v;
if (dtype != DataType.STRUCTURE) {
v = new Variable(ncfile, g, parent, vname, dtype, dimList);
} else if (utype != null) {
Structure s = new Structure(ncfile, g, parent, vname);
s.setDimensions(dimList);
v = s;
if (utype.flds == null)
utype.readFields();
//Coverity[FORWARD_NULL]
for (Field f : utype.flds) {
s.addMemberVariable(f.makeMemberVariable(g, s));
}
} else {
throw new IllegalStateException("Dunno what to with " + dtype);
}
if (cvttype.isUnsigned)
v.addAttribute(new Attribute(CDM.UNSIGNED, "true"));
if (dtype.isEnum()) {
EnumTypedef enumTypedef = g.findEnumeration(utype.name);
v.setEnumTypedef(enumTypedef);
}
return v;
}
private String makeDimList(int grpid, int ndimsp, int[] dims)
throws IOException {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < ndimsp; i++) {
byte[] name = new byte[Nc4prototypes.NC_MAX_NAME + 1];
int ret = nc4.nc_inq_dimname(grpid, dims[i], name);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
String dname = makeString(name);
sb.append(dname);
sb.append(" ");
}
return sb.toString();
}
private boolean nc_inq_var(Formatter f, int grpid, int varno) throws IOException {
byte[] name = new byte[Nc4prototypes.NC_MAX_NAME + 1];
IntByReference xtypep = new IntByReference();
IntByReference ndimsp = new IntByReference();
int[] dimids = new int[Nc4prototypes.NC_MAX_DIMS];
IntByReference nattsp = new IntByReference();
int ret = nc4.nc_inq_var(grpid, varno, name, xtypep, ndimsp, dimids, nattsp);
if (ret != 0)
return false;
String vname = makeString(name);
int typeid = xtypep.getValue();
ConvertedType cvt = convertDataType(typeid);
f.format("%s %s %s(", cvt.dt, cvt.isUnsigned ? "unsigned" : "", vname);
for (int i = 0; i < ndimsp.getValue(); i++) {
f.format("%d ", dimids[i]);
}
String dimList = makeDimList(grpid, ndimsp.getValue(), dimids);
f.format(") dims=(%s)%n", dimList);
return true;
}
//////////////////////////////////////////////////////////////////////////
static private class Vinfo {
final Group4 g4;
int varid, typeid;
UserType utype; // may be null
Vinfo(Group4 g4, int varid, int typeid) {
this.g4 = g4;
this.varid = varid;
this.typeid = typeid;
}
}
static private class Group4 {
final int grpid;
final Group g;
final Group4 parent;
Map dimHash;
Group4(int grpid, Group g, Group4 parent) {
this.grpid = grpid;
this.g = g;
this.parent = parent;
}
}
// Cannot be static because it references non-static parent class memebers
//Coverity[FB.SIC_INNER_SHOULD_BE_STATIC]
private class UserType {
int grpid;
int typeid;
String name;
int size; // the size of the user defined type
int baseTypeid; // the base typeid for vlen and enum types
long nfields; // the number of fields for enum and compound types
int typeClass; // the class of the user defined type: NC_VLEN, NC_OPAQUE, NC_ENUM, or NC_COMPOUND.
EnumTypedef e;
List flds;
UserType(int grpid, int typeid, String name, long size, int baseTypeid, long nfields, int typeClass)
throws IOException {
this.grpid = grpid;
this.typeid = typeid;
this.name = name;
this.size = (int) size;
this.baseTypeid = baseTypeid;
this.nfields = nfields;
this.typeClass = typeClass;
if (debugUserTypes) System.out.printf("%s%n", this);
if (typeClass == Nc4prototypes.NC_COMPOUND)
readFields();
}
DataType getEnumBaseType() {
// set the enum's basetype
if (baseTypeid > 0 && baseTypeid <= NC_MAX_ATOMIC_TYPE) {
DataType cdmtype = null;
boolean isunsigned = false;
switch (baseTypeid) {
case NC_CHAR:
case NC_UBYTE:
isunsigned = true;
//coverity[MISSING_BREAK]
case NC_BYTE:
cdmtype = DataType.ENUM1;
break;
case NC_USHORT:
isunsigned = true;
//coverity[MISSING_BREAK]
case NC_SHORT:
cdmtype = DataType.ENUM1;
break;
case NC_UINT:
isunsigned = true;
//coverity[MISSING_BREAK]
case NC_INT:
default:
cdmtype = DataType.ENUM4;
break;
}
// not supported this.e.setUnsigned(isunsigned); LOOK
return cdmtype;
}
return null;
}
void addField(Field fld) {
if (flds == null)
flds = new ArrayList<>(10);
flds.add(fld);
}
void setFields(List flds) {
this.flds = flds;
}
public String toString2() {
return "name='" + name + "' id=" + getDataTypeName(typeid) + " userType=" + getDataTypeName(typeClass)
+ " baseType=" + getDataTypeName(baseTypeid);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("UserType");
sb.append("{grpid=").append(grpid);
sb.append(", typeid=").append(typeid);
sb.append(", name='").append(name).append('\'');
sb.append(", size=").append(size);
sb.append(", baseTypeid=").append(baseTypeid);
sb.append(", nfields=").append(nfields);
sb.append(", typeClass=").append(typeClass);
sb.append(", e=").append(e);
sb.append('}');
return sb.toString();
}
void readFields() throws IOException {
for (int fldidx = 0; fldidx < nfields; fldidx++) {
byte[] fldname = new byte[Nc4prototypes.NC_MAX_NAME + 1];
IntByReference field_typeidp = new IntByReference();
IntByReference ndimsp = new IntByReference();
SizeTByReference offsetp = new SizeTByReference();
int[] dims = new int[Nc4prototypes.NC_MAX_DIMS];
int ret = nc4.nc_inq_compound_field(grpid, typeid, fldidx, fldname, offsetp, field_typeidp, ndimsp, dims);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
Field fld = new Field(grpid, typeid, fldidx, makeString(fldname), offsetp.getValue().intValue(),
field_typeidp.getValue(), ndimsp.getValue(), dims);
addField(fld);
if (debugUserTypes) System.out.printf(" %s add field= %s%n", name, fld);
}
}
}
// encapsolate the fields in a compound type
// Cannot be static because it references non-static parent class members
//Coverity[FB.SIC_INNER_SHOULD_BE_STATIC]
private class Field {
int grpid;
int typeid; // containing structure
int fldidx;
String name;
int offset;
int fldtypeid;
int ndims;
int[] dims;
ConvertedType ctype;
//int total_size;
Array data;
// grpid, varid, fldidx, fldname, offsetp, field_typeidp, ndimsp, dim_sizesp
Field(int grpid, int typeid, int fldidx, String name, int offset, int fldtypeid, int ndims, int[] dimz) {
this.grpid = grpid;
this.typeid = typeid;
this.fldidx = fldidx;
this.name = name;
this.offset = offset;
this.fldtypeid = fldtypeid;
// Reduce the stored dimensions to match the actual rank
// because some code (i.e. Section) is using this.dims.length
// to compute the rank.
this.ndims = ndims;
this.dims = new int[ndims];
System.arraycopy(dimz, 0, this.dims, 0, ndims);
ctype = convertDataType(fldtypeid);
//Section s = new Section(this.dims);
//total_size = (int) s.computeSize() * ctype.dt.getSize();
if (isVlen(fldtypeid)) {
int[] edims = new int[ndims + 1];
if (ndims > 0)
System.arraycopy(dimz, 0, edims, 0, ndims);
edims[ndims] = -1;
this.dims = edims;
this.ndims++;
}
}
public String toString2() {
return "name='" + name + " fldtypeid=" + getDataTypeName(fldtypeid) + " ndims=" + ndims + " offset=" + offset;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("Field");
sb.append("{grpid=").append(grpid);
sb.append(", typeid=").append(typeid);
sb.append(", fldidx=").append(fldidx);
sb.append(", name='").append(name).append('\'');
sb.append(", offset=").append(offset);
sb.append(", fldtypeid=").append(fldtypeid);
sb.append(", ndims=").append(ndims);
sb.append(", dims=").append(dims == null ? "null" : "");
for (int i = 0; dims != null && i < dims.length; ++i)
sb.append(i == 0 ? "" : ", ").append(dims[i]);
sb.append(", dtype=").append(ctype.dt);
if (ctype.isUnsigned) sb.append("(unsigned)");
if (ctype.isVlen) sb.append("(vlen)");
sb.append('}');
return sb.toString();
}
/* Variable makeMemberVariable(Group g, Structure parent)
{
Variable v = new Variable(ncfile, g, parent, name);
v.setDataType(convertDataType(fldtypeid).dt);
if(isUnsigned(fldtypeid))
v.addAttribute(new Attribute(CDM.UNSIGNED, "true"));
if(ctype.isVlen) {
v.setDimensions("*");
} else {
try {
v.setDimensionsAnonymous(dims);
} catch (InvalidRangeException e) {
e.printStackTrace();
}
}
return v;
} */
Variable makeMemberVariable(Group g, Structure parent)
throws IOException {
Variable v = makeVariable(g, parent, name, fldtypeid, "");
//if(ctype.isVlen) {
//v.setDimensions("*");
//} else
{
try {
v.setDimensionsAnonymous(dims); // LOOK no shared dimensions ?
} catch (InvalidRangeException e) {
e.printStackTrace();
}
}
return v;
}
}
private void makeUserTypes(int grpid, Group g) throws IOException {
// find user types in this group
IntByReference ntypesp = new IntByReference();
int ret = nc4.nc_inq_typeids(grpid, ntypesp, Pointer.NULL);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
int ntypes = ntypesp.getValue();
if (ntypes == 0) return;
int[] xtypes = new int[ntypes];
ret = nc4.nc_inq_typeids(grpid, ntypesp, xtypes);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
// for each defined "user type", get information, store in Map
for (int typeid : xtypes) {
byte[] nameb = new byte[Nc4prototypes.NC_MAX_NAME + 1];
SizeTByReference sizep = new SizeTByReference();
IntByReference baseType = new IntByReference();
SizeTByReference nfieldsp = new SizeTByReference();
IntByReference classp = new IntByReference();
/*
ncid The ncid for the group containing the user defined type.
xtype The typeid for this type, as returned by nc_def_compound, nc_def_opaque, nc_def_enum, nc_def_vlen, or nc_inq_var.
name If non-NULL, the name of the user defined type will be copied here. It will be NC_MAX_NAME bytes or less.
sizep If non-NULL, the (in-memory) size of the type in bytes will be copied here. VLEN type size is the size of nc_vlen_t.
String size is returned as the size of a character pointer. The size may be used to malloc space for the data, no matter what the type.
nfieldsp If non-NULL, the number of fields will be copied here for enum and compound types.
classp Return the class of the user defined type, NC_VLEN, NC_OPAQUE, NC_ENUM, or NC_COMPOUND.
*/
ret = nc4.nc_inq_user_type(grpid, typeid, nameb, sizep, baseType, nfieldsp, classp); // size_t
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
String name = makeString(nameb);
int utype = classp.getValue();
if (debug) System.out.printf(" user type id=%d name=%s size=%d baseType=%d nfields=%d class=%d%n",
typeid, name, sizep.getValue().longValue(), baseType.getValue(), nfieldsp.getValue().longValue(), utype);
UserType ut = new UserType(grpid, typeid, name, sizep.getValue().longValue(), baseType.getValue(),
nfieldsp.getValue().longValue(), utype);
userTypes.put(typeid, ut);
if (utype == Nc4prototypes.NC_ENUM) {
Map map = makeEnum(grpid, typeid);
ut.e = new EnumTypedef(name, map, ut.getEnumBaseType());
g.addEnumeration(ut.e);
} else if (utype == Nc4prototypes.NC_OPAQUE) {
byte[] nameo = new byte[Nc4prototypes.NC_MAX_NAME + 1];
SizeTByReference sizep2 = new SizeTByReference();
ret = nc4.nc_inq_opaque(grpid, typeid, nameo, sizep2);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
// doesnt seem to be any new info
// String nameos = makeString(nameo);
//System.out.printf(" opaque type=%d name=%s size=%d %n ",
// typeid, nameos, sizep2.getValue().longValue());
}
}
}
static public void
dumpbytes(byte[] bytes, int start, int len, String tag)
{
System.err.println("++++++++++ " + tag + " ++++++++++ ");
int stop = start + len;
try {
for(int i = 0; i < stop; i++) {
byte b = bytes[i];
int ib = (int) b;
int ub = (ib & 0xFF);
char c = (char) ub;
String s = Character.toString(c);
if(c == '\r') s = "\\r";
else if(c == '\n') s = "\\n";
else if(c < ' ') s = "?";
System.err.printf("[%03d] %02x %03d %4d '%s'", i, ub, ub, ib, s);
System.err.println();
System.err.flush();
}
} catch (Exception e) {
System.err.println("failure:" + e);
} finally {
System.err.println("++++++++++ " + tag + " ++++++++++ ");
System.err.flush();
}
}
private Map makeEnum(int grpid, int xtype)
throws IOException {
byte[] nameb = new byte[Nc4prototypes.NC_MAX_NAME + 1];
IntByReference baseType = new IntByReference();
SizeTByReference baseSize = new SizeTByReference();
SizeTByReference numMembers = new SizeTByReference();
int ret = nc4.nc_inq_enum(grpid, xtype, nameb, baseType, baseSize, numMembers);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
int nmembers = numMembers.getValue().intValue();
//System.out.printf(" type=%d name=%s baseType=%d baseType=%d numMembers=%d %n ",
// xtype, name, baseType.getValue(), baseSize.getValue().longValue(), nmembers);
Map map = new HashMap(2 * nmembers);
for (int i = 0; i < nmembers; i++) {
byte[] mnameb = new byte[Nc4prototypes.NC_MAX_NAME + 1];
IntByReference value = new IntByReference();
ret = nc4.nc_inq_enum_member(grpid, xtype, i, mnameb, value); // void *
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
String mname = makeString(mnameb);
//System.out.printf(" member name=%s value=%d %n ", mname, value.getValue());
map.put(value.getValue(), mname);
}
return map;
}
/////////////////////////////////////////////////////////////////////////////////
@Override
public Array readData(Variable v2, Section section)
throws IOException, InvalidRangeException {
Vinfo vinfo = (Vinfo) v2.getSPobject();
int vlen = (int) v2.getSize();
int len = (int) section.computeSize();
if (vlen == len) // entire array
return readDataAll(vinfo.g4.grpid, vinfo.varid, vinfo.typeid, v2.getShapeAsSection());
//if(!section.isStrided()) // optimisation for unstrided section
// return readUnstrided(vinfo.grpid, vinfo.varid, vinfo.typeid, section);
return readDataSection(vinfo.g4.grpid, vinfo.varid, vinfo.typeid, section);
}
private Array readDataSection(int grpid, int varid, int typeid, Section section)
throws IOException, InvalidRangeException {
// general sectioning with strides
SizeT[] origin = convertSizeT(section.getOrigin());
SizeT[] shape = convertSizeT(section.getShape());
SizeT[] stride = convertSizeT(section.getStride());
boolean isUnsigned = isUnsigned(typeid);
int len = (int) section.computeSize();
Array values;
switch (typeid) {
// int nc_get_vars_schar(int ncid, int varid, long[] startp, long[] countp, int[] stridep, byte[] ip);
case Nc4prototypes.NC_BYTE:
case Nc4prototypes.NC_UBYTE:
byte[] valb = new byte[len];
int ret;
ret = isUnsigned ? nc4.nc_get_vars_uchar(grpid, varid, origin, shape, stride, valb)
: nc4.nc_get_vars_schar(grpid, varid, origin, shape, stride, valb);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
values = Array.factory(DataType.BYTE.getPrimitiveClassType(), section.getShape(), valb);
break;
case Nc4prototypes.NC_CHAR:
byte[] valc = new byte[len];
ret = nc4.nc_get_vars_text(grpid, varid, origin, shape, stride, valc);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
values = Array.factory(DataType.CHAR.getPrimitiveClassType(), section.getShape(), IospHelper.convertByteToChar(valc));
break;
case Nc4prototypes.NC_DOUBLE:
double[] vald = new double[len];
ret = nc4.nc_get_vars_double(grpid, varid, origin, shape, stride, vald);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
values = Array.factory(DataType.DOUBLE.getPrimitiveClassType(), section.getShape(), vald);
break;
case Nc4prototypes.NC_FLOAT:
float[] valf = new float[len];
ret = nc4.nc_get_vars_float(grpid, varid, origin, shape, stride, valf);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
values = Array.factory(DataType.FLOAT.getPrimitiveClassType(), section.getShape(), valf);
break;
case Nc4prototypes.NC_INT:
int[] vali = new int[len];
ret = isUnsigned ? nc4.nc_get_vars_uint(grpid, varid, origin, shape, stride, vali)
: nc4.nc_get_vars_int(grpid, varid, origin, shape, stride, vali);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
values = Array.factory(DataType.INT.getPrimitiveClassType(), section.getShape(), vali);
break;
case Nc4prototypes.NC_INT64:
long[] vall = new long[len];
ret = isUnsigned ? nc4.nc_get_vars_ulonglong(grpid, varid, origin, shape, stride, vall)
: nc4.nc_get_vars_longlong(grpid, varid, origin, shape, stride, vall);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
values = Array.factory(DataType.LONG.getPrimitiveClassType(), section.getShape(), vall);
break;
case Nc4prototypes.NC_SHORT:
short[] vals = new short[len];
ret = isUnsigned ? nc4.nc_get_vars_ushort(grpid, varid, origin, shape, stride, vals)
: nc4.nc_get_vars_short(grpid, varid, origin, shape, stride, vals);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
values = Array.factory(DataType.SHORT.getPrimitiveClassType(), section.getShape(), vals);
break;
case Nc4prototypes.NC_STRING:
String[] valss = new String[len];
ret = nc4.nc_get_vars_string(grpid, varid, origin, shape, stride, valss);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
return Array.factory(DataType.STRING.getPrimitiveClassType(), section.getShape(), valss);
default:
UserType userType = userTypes.get(typeid);
if (userType == null) {
throw new IOException("Unknown userType == " + typeid);
} else if (userType.typeClass == Nc4prototypes.NC_ENUM) {
return readDataSection(grpid, varid, userType.baseTypeid, section);
} else if (userType.typeClass == Nc4prototypes.NC_VLEN) { // cannot subset
return readVlen(grpid, varid, userType, section);
} else if (userType.typeClass == Nc4prototypes.NC_OPAQUE) {
return readOpaque(grpid, varid, section, userType.size);
} else if (userType.typeClass == Nc4prototypes.NC_COMPOUND) {
return readCompound(grpid, varid, section, userType);
}
throw new IOException("Unsupported userType = " + typeid + " userType= " + userType);
}
return values;
}
// read entire array
private Array readDataAll(int grpid, int varid, int typeid, Section section)
throws IOException, InvalidRangeException {
int ret;
int len = (int) section.computeSize();
int[] shape = section.getShape();
switch (typeid) {
case Nc4prototypes.NC_UBYTE:
byte[] valbu = new byte[len];
ret = nc4.nc_get_var_ubyte(grpid, varid, valbu);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
return Array.factory(DataType.BYTE.getPrimitiveClassType(), shape, valbu);
case Nc4prototypes.NC_BYTE:
byte[] valb = new byte[len];
ret = nc4.nc_get_var_schar(grpid, varid, valb);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
return Array.factory(DataType.BYTE.getPrimitiveClassType(), shape, valb);
case Nc4prototypes.NC_CHAR:
byte[] valc = new byte[len];
ret = nc4.nc_get_var_text(grpid, varid, valc);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
char[] cvals = IospHelper.convertByteToChar(valc);
return Array.factory(DataType.CHAR.getPrimitiveClassType(), shape, cvals);
case Nc4prototypes.NC_DOUBLE:
double[] vald = new double[len];
ret = nc4.nc_get_var_double(grpid, varid, vald);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
return Array.factory(DataType.DOUBLE.getPrimitiveClassType(), shape, vald);
case Nc4prototypes.NC_FLOAT:
float[] valf = new float[len];
ret = nc4.nc_get_var_float(grpid, varid, valf);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
return Array.factory(DataType.FLOAT.getPrimitiveClassType(), shape, valf);
case Nc4prototypes.NC_INT:
int[] vali = new int[len];
ret = nc4.nc_get_var_int(grpid, varid, vali);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
return Array.factory(DataType.INT.getPrimitiveClassType(), shape, vali);
case Nc4prototypes.NC_INT64:
long[] vall = new long[len];
ret = nc4.nc_get_var_longlong(grpid, varid, vall);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
return Array.factory(DataType.LONG.getPrimitiveClassType(), shape, vall);
case Nc4prototypes.NC_UINT64:
long[] vallu = new long[len];
ret = nc4.nc_get_var_ulonglong(grpid, varid, vallu);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
return Array.factory(DataType.LONG.getPrimitiveClassType(), shape, vallu);
case Nc4prototypes.NC_SHORT:
short[] vals = new short[len];
ret = nc4.nc_get_var_short(grpid, varid, vals);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
return Array.factory(DataType.SHORT.getPrimitiveClassType(), shape, vals);
case Nc4prototypes.NC_USHORT:
short[] valsu = new short[len];
ret = nc4.nc_get_var_ushort(grpid, varid, valsu);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
return Array.factory(DataType.SHORT.getPrimitiveClassType(), shape, valsu);
case Nc4prototypes.NC_UINT:
int[] valiu = new int[len];
ret = nc4.nc_get_var_uint(grpid, varid, valiu);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
return Array.factory(DataType.INT.getPrimitiveClassType(), shape, valiu);
case Nc4prototypes.NC_STRING:
String[] valss = new String[len];
ret = nc4.nc_get_var_string(grpid, varid, valss);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
return Array.factory(DataType.STRING.getPrimitiveClassType(), shape, valss);
default:
UserType userType = userTypes.get(typeid);
if (userType == null) {
throw new IOException("Unknown userType == " + typeid);
} else if (userType.typeClass == Nc4prototypes.NC_ENUM) {
int buffSize = len * userType.size;
byte[] bbuff = new byte[buffSize];
// read in the data
ret = nc4.nc_get_var(grpid, varid, bbuff);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
ByteBuffer bb = ByteBuffer.wrap(bbuff);
bb.order(ByteOrder.nativeOrder()); // c library returns in native order i hope
switch (userType.baseTypeid) {
case Nc4prototypes.NC_BYTE:
case Nc4prototypes.NC_UBYTE:
return Array.factory(DataType.BYTE, shape, bb);
case Nc4prototypes.NC_SHORT:
case Nc4prototypes.NC_USHORT:
return Array.factory(DataType.SHORT, shape, bb);
}
throw new IOException("unknown type " + userType.baseTypeid);
} else if (userType.typeClass == Nc4prototypes.NC_VLEN) {
return readVlen(grpid, varid, userType, section);
} else if (userType.typeClass == Nc4prototypes.NC_OPAQUE) {
return readOpaque(grpid, varid, section, userType.size);
} else if (userType.typeClass == Nc4prototypes.NC_COMPOUND) {
return readCompound(grpid, varid, section, userType);
}
throw new IOException("Unsupported userType = " + typeid + " userType= " + userType);
}
}
private Array readCompound(int grpid, int varid, Section section, UserType userType)
throws IOException {
SizeT[] origin = convertSizeT(section.getOrigin());
SizeT[] shape = convertSizeT(section.getShape());
SizeT[] stride = convertSizeT(section.getStride());
int len = (int) section.computeSize();
int buffSize = len * userType.size;
byte[] bbuff = new byte[buffSize];
// read in the data
int ret;
ret = nc4.nc_get_vars(grpid, varid, origin, shape, stride, bbuff);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
ByteBuffer bb = ByteBuffer.wrap(bbuff);
bb.order(ByteOrder.nativeOrder()); // c library returns in native order i hope
/*
This does not seem right since the user type does not
normally appear in the CDM representation.
*/
StructureMembers sm = createStructureMembers(userType);
ArrayStructureBB asbb = new ArrayStructureBB(sm, section.getShape(), bb, 0);
// find and convert String and vlen fields, put on asbb heap
int destPos = 0;
for (int i = 0; i < len; i++) { // loop over each structure
convertHeap(asbb, destPos, sm);
destPos += userType.size;
}
return asbb;
}
private StructureMembers createStructureMembers(UserType userType) {
StructureMembers sm = new StructureMembers(userType.name);
for (Field fld : userType.flds) {
StructureMembers.Member m = sm.addMember(fld.name, null, null, fld.ctype.dt, fld.dims);
m.setDataParam(fld.offset);
/* This should already have been taken care of
if(fld.ctype.isVlen) {m.setShape(new int[]{-1}); } */
if (fld.ctype.dt == DataType.STRUCTURE) {
UserType nested_utype = userTypes.get(fld.fldtypeid);
StructureMembers nested_sm = createStructureMembers(nested_utype);
m.setStructureMembers(nested_sm);
}
}
sm.setStructureSize(userType.size);
return sm;
}
// LOOK: handling nested ??
private void convertHeap(ArrayStructureBB asbb, int pos, StructureMembers sm) throws IOException {
ByteBuffer bb = asbb.getByteBuffer();
for (StructureMembers.Member m : sm.getMembers()) {
if (m.getDataType() == DataType.STRING) {
int size = m.getSize();
int destPos = pos + m.getDataParam();
String[] result = new String[size];
for (int i = 0; i < size; i++) {
long addr = getNativeAddr(pos,bb);
Pointer p = new Pointer(addr);
result[i] = p.getString(0, false);
}
int index = asbb.addObjectToHeap(result);
bb.putInt(destPos, index); // overwrite with the index into the StringHeap
} else if (m.isVariableLength()) {
// We need to do like readVLEN, but store the resulting array
// in the asbb heap (a bit of a hack).
// we assume that pos "points" to the beginning of this structure instance
// and so pos + m.getDataParam() "points" to field m in this structure instance.
int nc_vlen_t_size = (new Nc4prototypes.Vlen_t()).size();
int startPos = pos + m.getDataParam();
// Compute rank and size upto the first (and ideally last) VLEN
int[] fieldshape = m.getShape();
int prefixrank = 0;
int size = 1;
for (; prefixrank < fieldshape.length; prefixrank++) {
if (fieldshape[prefixrank] < 0) break;
size *= fieldshape[prefixrank];
}
assert size == m.getSize() : "Internal error: field size mismatch";
Array[] fieldarray = new Array[size]; // hold all the nc_vlen_t instance data
// destPos will point to each nc_vlen_t instance in turn
// assuming we have 'size' such instances in a row.
int destPos = startPos;
for (int i = 0; i < size; i++) {
// vlenarray extracts the i'th nc_vlen_t contents (struct not supported).
Array vlenArray = decodeVlen(m.getDataType(), destPos, bb);
fieldarray[i] = vlenArray;
destPos += nc_vlen_t_size;
}
Array result = null;
if (prefixrank == 0) // if scalar, return just the singleton vlen array
result = fieldarray[0];
else if (prefixrank == 1)
result = new ArrayObject(fieldarray[0].getClass(), new int[]{size}, fieldarray);
else {
// Otherwise create and fill in an n-dimensional Array Of Arrays
int[] newshape = new int[prefixrank];
System.arraycopy(fieldshape, 0, newshape, 0, prefixrank);
Array ndimarray = Array.factory(Array.class, newshape);
// Transfer the elements of data into the n-dim arrays
IndexIterator iter = ndimarray.getIndexIterator();
for (int i = 0; iter.hasNext(); i++) {
iter.setObjectNext(fieldarray[i]);
}
result = ndimarray;
}
// Store result in the heap
int index = asbb.addObjectToHeap(result);
bb.order(ByteOrder.nativeOrder()); // the string index is always written in "native order"
bb.putInt(startPos, index); // overwrite with the index into the StringHeap
}
}
}
private void
decodeVlenField(Field fld, UserType userType, int pos, int idx, ByteBuffer bbuff)
throws IOException {
ConvertedType cvt = convertDataType(userType.baseTypeid);
Array array = decodeVlen(cvt.dt, pos, bbuff);
fld.data.setObject(idx, array);
if (cvt.isUnsigned) fld.data.setUnsigned(true);
}
private Array
decodeVlen(DataType dt, int pos, ByteBuffer bbuff)
throws IOException {
Array array = null;
int n = (int) bbuff.getLong(pos); // Note that this does not increment the buffer position
long addr = getNativeAddr(pos + NativeLong.SIZE,bbuff); // LOOK: this assumes 64 bit pointers
Pointer p = new Pointer(addr);
Object data = null;
switch (dt) {
case BOOLEAN: /*byte[]*/
data = p.getByteArray(0, n);
break;
case ENUM1:
case BYTE: /*byte[]*/
data = p.getByteArray(0, n);
break;
case ENUM2:
case SHORT: /*short[]*/
data = p.getShortArray(0, n);
break;
case ENUM4:
case INT: /*int[]*/
data = p.getIntArray(0, n);
break;
case LONG: /*long[]*/
data = p.getLongArray(0, n);
break;
case FLOAT: /*float[]*/
data = p.getFloatArray(0, n);
break;
case DOUBLE: /*double[]*/
data = p.getDoubleArray(0, n);
break;
case CHAR: /*char[]*/
data = p.getCharArray(0, n);
break;
case STRING: /*String[]*/
// For now we need to use p.getString()
// because p.getStringArray(int,int) does not exist
// in jna version 3.0.9, but does exist in
// verssion 4.0 and possibly some intermediate versions
String[] stringdata = new String[n];
for (int i = 0; i < n; i++)
stringdata[i] = p.getString(i * 8);
data = stringdata;
break;
case OPAQUE:
case STRUCTURE:
default:
throw new IllegalStateException();
}
array = Array.factory(dt, new int[]{n}, data);
return array;
}
/**
* Note that this only works for atomic base types;
* structures will fail.
*/
Array readVlen(int grpid, int varid, UserType userType, Section section)
throws IOException {
// Read all the vlen pointers
int len = (int) section.computeSize();
Nc4prototypes.Vlen_t[] vlen = new Nc4prototypes.Vlen_t[len];
int ret = nc4.nc_get_var(grpid, varid, vlen);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
// Compute rank upto the first VLEN
int prefixrank = 0;
for (; prefixrank < section.getRank(); prefixrank++) {
if (section.getRange(prefixrank) == Range.VLEN) break;
}
//DataType dtype = convertDataType(userType.baseTypeid);
//ArrayObject.D1 vlenArray = new ArrayObject.D1( dtype.getPrimitiveClassType(), len);
// Collect the vlen's data arrays
Object[] data = new Object[len];
switch (userType.baseTypeid) {
case Nc4prototypes.NC_UINT:
case Nc4prototypes.NC_INT:
for (int i = 0; i < len; i++) {
int slen = vlen[i].len;
//Coverity[FB.NP_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD]
int[] ba = vlen[i].p.getIntArray(0, slen);
data[i] = Array.factory(DataType.INT, new int[]{slen}, ba);
}
break;
case Nc4prototypes.NC_USHORT:
case Nc4prototypes.NC_SHORT:
for (int i = 0; i < len; i++) {
int slen = vlen[i].len;
//Coverity[FB.NP_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD]
short[] ba = vlen[i].p.getShortArray(0, slen);
data[i] = Array.factory(DataType.SHORT, new int[]{slen}, ba);
}
break;
case Nc4prototypes.NC_FLOAT:
for (int i = 0; i < len; i++) {
int slen = vlen[i].len;
//Coverity[FB.NP_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD]
float[] ba = vlen[i].p.getFloatArray(0, slen);
data[i] = Array.factory(DataType.FLOAT, new int[]{slen}, ba);
}
break;
default:
throw new UnsupportedOperationException("Vlen type " + userType.baseTypeid + " = " + convertDataType(userType.baseTypeid));
}
if (prefixrank == 0) { // if scalar, return just the len Array
return (Array) data[0];
} else if (prefixrank == 1)
return (Array) new ArrayObject(data[0].getClass(), new int[]{len}, data);
// Otherwise create and fill in an n-dimensional Array Of Arrays
int[] shape = new int[prefixrank];
for (int i = 0; i < prefixrank; i++)
shape[i] = section.getRange(i).length();
Array ndimarray = Array.factory(Array.class, shape);
// Transfer the elements of data into the n-dim arrays
IndexIterator iter = ndimarray.getIndexIterator();
for (int i = 0; iter.hasNext(); i++) {
iter.setObjectNext(data[i]);
}
return ndimarray;
}
// opaques use ArrayObjects of ByteBuffer
private Array readOpaque(int grpid, int varid, Section section, int size)
throws IOException, InvalidRangeException {
int ret;
SizeT[] origin = convertSizeT(section.getOrigin());
SizeT[] shape = convertSizeT(section.getShape());
SizeT[] stride = convertSizeT(section.getStride());
int len = (int) section.computeSize();
byte[] bbuff = new byte[len * size];
ret = nc4.nc_get_vars(grpid, varid, origin, shape, stride, bbuff);
if(DEBUG)
dumpbytes(bbuff,0,bbuff.length,"readOpaque");
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
int[] intshape;
if (shape != null) {
// fix: this is ignoring the rank of section.
// was: ArrayObject values = new ArrayObject(ByteBuffer.class, new int[]{len});
intshape = new int[shape.length];
for (int i = 0; i < intshape.length; i++) {
intshape[i] = shape[i].intValue();
}
} else
intshape = new int[]{1};
ArrayObject values = new ArrayObject(ByteBuffer.class, intshape);
int count = 0;
IndexIterator ii = values.getIndexIterator();
while (ii.hasNext()) {
ii.setObjectNext(ByteBuffer.wrap(bbuff, count * size, size));
count++;
}
return values;
}
/* private Array readEnum(int grpid, int varid, int baseType, int len, int[] shape)
throws IOException, InvalidRangeException
{
int ret;
ConvertedType ctype = convertDataType(baseType);
int elemSize = ctype.dt.getSize();
ByteBuffer bb = ByteBuffer.allocate(len * elemSize);
ret = nc4.nc_get_var(grpid, varid, bb);
if(ret != 0)
throw new IOException(ret+": "+nc4.nc_strerror(ret)) ;
switch (baseType) {
case NCLibrary.NC_BYTE:
case NCLibrary.NC_UBYTE:
return Array.factory( DataType.BYTE.getPrimitiveClassType(), shape, bb.array());
case NCLibrary.NC_SHORT:
case NCLibrary.NC_USHORT:
ShortBuffer sb = bb.asShortBuffer();
return Array.factory( DataType.BYTE.getPrimitiveClassType(), shape, sb.array());
case NCLibrary.NC_INT:
case NCLibrary.NC_UINT:
IntBuffer ib = bb.asIntBuffer();
return Array.factory( DataType.BYTE.getPrimitiveClassType(), shape, ib.array());
}
return null;
} */
private boolean isUnsigned(int type) {
return (type == Nc4prototypes.NC_UBYTE) || (type == Nc4prototypes.NC_USHORT) ||
(type == Nc4prototypes.NC_UINT) || (type == Nc4prototypes.NC_UINT64);
}
private boolean isVlen(int type) {
UserType userType = userTypes.get(type);
return (userType != null) && (userType.typeClass == Nc4prototypes.NC_VLEN);
}
private boolean isStride1(int[] strides) {
if (strides == null) return true;
for (int stride : strides) {
if (stride != 1) return false;
}
return true;
}
private SizeT[] convertSizeT(int[] from) {
if (from.length == 0) return null;
SizeT[] to = new SizeT[from.length];
for (int i = 0; i < from.length; i++)
to[i] = new SizeT(from[i]);
return to;
}
static public String show(SizeT[] inta) {
if (inta == null) return "null";
Formatter f = new Formatter();
for (SizeT i : inta) f.format("%d, ", i.longValue());
return f.toString();
}
// Cannot be static because it references non-stati parent class members
//Coverity[FB.SIC_INNER_SHOULD_BE_STATIC]
private static class ConvertedType {
DataType dt;
boolean isUnsigned;
boolean isVlen;
ConvertedType(DataType dt, boolean isUnsigned) {
this.dt = dt;
this.isUnsigned = isUnsigned;
}
}
private int convertDataType(DataType dt, boolean isUnsigned) {
switch (dt) {
case BYTE:
return isUnsigned ? Nc4prototypes.NC_UBYTE : Nc4prototypes.NC_BYTE;
case CHAR:
return Nc4prototypes.NC_CHAR;
case DOUBLE:
return Nc4prototypes.NC_DOUBLE;
case FLOAT:
return Nc4prototypes.NC_FLOAT;
case INT:
return isUnsigned ? Nc4prototypes.NC_UINT : Nc4prototypes.NC_INT;
case LONG:
return isUnsigned ? Nc4prototypes.NC_UINT64 : Nc4prototypes.NC_INT64;
case SHORT:
return isUnsigned ? Nc4prototypes.NC_USHORT : Nc4prototypes.NC_SHORT;
case STRING:
return Nc4prototypes.NC_STRING;
case ENUM1:
case ENUM2:
case ENUM4:
return Nc4prototypes.NC_ENUM;
case OPAQUE:
log.warn("Skipping Opaque Type");
return -1;
case STRUCTURE:
return Nc4prototypes.NC_COMPOUND;
}
throw new IllegalArgumentException("unimplemented type == " + dt);
}
private ConvertedType convertDataType(int type) {
switch (type) {
case Nc4prototypes.NC_BYTE:
return new ConvertedType(DataType.BYTE, false);
case Nc4prototypes.NC_UBYTE:
return new ConvertedType(DataType.BYTE, true);
case Nc4prototypes.NC_CHAR:
return new ConvertedType(DataType.CHAR, false);
case Nc4prototypes.NC_SHORT:
return new ConvertedType(DataType.SHORT, false);
case Nc4prototypes.NC_USHORT:
return new ConvertedType(DataType.SHORT, true);
case Nc4prototypes.NC_INT:
return new ConvertedType(DataType.INT, false);
case Nc4prototypes.NC_UINT:
return new ConvertedType(DataType.INT, true);
case Nc4prototypes.NC_INT64:
return new ConvertedType(DataType.LONG, false);
case Nc4prototypes.NC_UINT64:
return new ConvertedType(DataType.LONG, true);
case Nc4prototypes.NC_FLOAT:
return new ConvertedType(DataType.FLOAT, false);
case Nc4prototypes.NC_DOUBLE:
return new ConvertedType(DataType.DOUBLE, false);
case Nc4prototypes.NC_ENUM:
return new ConvertedType(DataType.ENUM1, false); // LOOK width ??
case Nc4prototypes.NC_STRING:
return new ConvertedType(DataType.STRING, false);
default:
UserType userType = userTypes.get(type);
if (userType == null)
throw new IllegalArgumentException("unknown type == " + type);
switch (userType.typeClass) {
case Nc4prototypes.NC_ENUM:
return new ConvertedType(DataType.ENUM1, false);
case Nc4prototypes.NC_COMPOUND:
return new ConvertedType(DataType.STRUCTURE, false);
case Nc4prototypes.NC_OPAQUE:
return new ConvertedType(DataType.OPAQUE, false);
case Nc4prototypes.NC_VLEN:
ConvertedType result = convertDataType(userType.baseTypeid);
result.isVlen = true;
return result;
}
throw new IllegalArgumentException("unknown type == " + type);
}
}
private String getDataTypeName(int type) {
switch (type) {
case Nc4prototypes.NC_BYTE:
return "byte";
case Nc4prototypes.NC_UBYTE:
return "ubyte";
case Nc4prototypes.NC_CHAR:
return "char";
case Nc4prototypes.NC_SHORT:
return "short";
case Nc4prototypes.NC_USHORT:
return "ushort";
case Nc4prototypes.NC_INT:
return "int";
case Nc4prototypes.NC_UINT:
return "uint";
case Nc4prototypes.NC_INT64:
return "long";
case Nc4prototypes.NC_UINT64:
return "ulong";
case Nc4prototypes.NC_FLOAT:
return "float";
case Nc4prototypes.NC_DOUBLE:
return "double";
case Nc4prototypes.NC_ENUM:
return "enum";
case Nc4prototypes.NC_STRING:
return "string";
case Nc4prototypes.NC_COMPOUND:
return "struct";
case Nc4prototypes.NC_OPAQUE:
return "opaque";
case Nc4prototypes.NC_VLEN:
return "vlen";
default:
UserType userType = userTypes.get(type);
if (userType == null)
return "unknown type " + type;
switch (userType.typeClass) {
case Nc4prototypes.NC_ENUM:
return "userType-enum";
case Nc4prototypes.NC_COMPOUND:
return "userType-struct";
case Nc4prototypes.NC_OPAQUE:
return "userType-opaque";
case Nc4prototypes.NC_VLEN:
return "userType-vlen";
}
return "unknown userType " + userType.typeClass;
}
}
//////////////////////////////////////////////////////////////////////
// writing data
@Override
public void create(String filename, NetcdfFile ncfile, int extra, long preallocateSize, boolean largeFile) throws IOException {
if (!isClibraryPresent()) {
throw new UnsupportedOperationException("Couldn't load NetCDF C library (see log for details).");
}
this.ncfile = ncfile;
// finish any structures
ncfile.finish();
// create new file
if (debug) System.out.println("create " + ncfile.getLocation());
int ret;
/* IntByReference oldFormat = new IntByReference();
int ret = nc4.nc_set_default_format(defineFormat(), oldFormat);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret)); */
IntByReference ncidp = new IntByReference();
ret = nc4.nc_create(filename, createMode(), ncidp);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
ncid = ncidp.getValue();
_setFill();
createGroup(new Group4(ncid, ncfile.getRootGroup(), null));
// done with define mode
nc4.nc_enddef(ncid);
if (debugWrite) System.out.printf("create done%n%n");
}
/*
cmode The creation mode flag. The following flags are available:
NC_NOCLOBBER (do not overwrite existing file),
NC_SHARE (limit write caching - netcdf classic files onlt),
NC_64BIT_OFFSET (create 64-bit offset file),
NC_NETCDF4 (create netCDF-4/HDF5 file),
NC_CLASSIC_MODEL (enforce netCDF classic mode on netCDF-4/HDF5 files),
NC_DISKLESS (store data only in memory),
NC_MMAP (use MMAP for NC_DISKLESS), and
NC_WRITE. See discussion below.
*/
private int createMode() {
int ret = nc4.NC_CLOBBER;
switch (version) {
case netcdf4:
ret |= nc4.NC_NETCDF4;
break;
case netcdf4_classic:
ret |= nc4.NC_NETCDF4 | nc4.NC_CLASSIC_MODEL;
break;
}
return ret;
}
/*
#define NC_FORMAT_CLASSIC (1)
#define NC_FORMAT_64BIT (2)
#define NC_FORMAT_NETCDF4 (3)
#define NC_FORMAT_NETCDF4_CLASSIC (4)
*/
private int defineFormat() {
switch (version) {
case netcdf4:
return Nc4prototypes.NC_FORMAT_NETCDF4;
case netcdf4_classic:
return Nc4prototypes.NC_FORMAT_NETCDF4_CLASSIC;
case netcdf3c:
return Nc4prototypes.NC_FORMAT_CLASSIC;
case netcdf3c64:
return Nc4prototypes.NC_FORMAT_64BIT;
}
throw new IllegalStateException("version = " + version);
}
private void createGroup(Group4 g4) throws IOException {
groupHash.put(g4.g, g4.grpid);
g4.dimHash = new HashMap<>();
// attributes
for (Attribute att : g4.g.getAttributes())
writeAttribute(g4.grpid, Nc4prototypes.NC_GLOBAL, att, null);
// dimensions
for (Dimension dim : g4.g.getDimensions()) {
int dimid = addDimension(g4.grpid, dim.getShortName(), dim.getLength());
g4.dimHash.put(dim, dimid);
if (debugWrite)
System.out.printf(" create dim '%s' (%d) in group '%s'%n", dim.getShortName(), dimid, g4.g.getFullName());
}
// a type must be created for each structure.
// LOOK we should look for variables with the same structure type.
for (Variable v : g4.g.getVariables()) {
switch (v.getDataType()) {
case STRUCTURE:
createCompoundType(g4, (Structure) v);
break;
}
}
// variables
for (Variable v : g4.g.getVariables()) {
createVariable(g4, v);
}
// groups
for (Group nested : g4.g.getGroups()) {
IntByReference grpidp = new IntByReference();
int ret = nc4.nc_def_grp(g4.grpid, nested.getShortName(), grpidp);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
int nestedId = grpidp.getValue();
createGroup(new Group4(nestedId, nested, g4));
}
}
private void createVariable(Group4 g4, Variable v) throws IOException {
int[] dimids = new int[v.getRank()];
int count = 0;
for (Dimension d : v.getDimensions()) {
int dimid;
if (!d.isShared()) {
dimid = addDimension(g4.grpid, v.getShortName() + "_Dim" + count, d.getLength());
} else {
dimid = findDimensionId(g4, d);
}
if (debugDim)
System.out.printf(" use dim '%s' (%d) in variable '%s'%n", d.getShortName(), dimid, v.getShortName());
dimids[count++] = dimid;
}
int typid;
Vinfo vinfo;
if (v instanceof Structure) { // g4 and typid was stored in vinfo in createCompoundType
vinfo = (Vinfo) v.getSPobject();
typid = vinfo.typeid;
} else {
typid = convertDataType(v.getDataType(), v.isUnsigned());
if (typid < 0) return; // not implemented yet
vinfo = new Vinfo(g4, -1, typid);
}
if (debugWrite) System.out.printf("adding variable %s (typeid %d) %n", v.getShortName(), typid);
IntByReference varidp = new IntByReference();
int ret = nc4.nc_def_var(g4.grpid, v.getShortName(), new SizeT(typid), dimids.length, dimids, varidp);
if (ret != 0)
throw new IOException("ret=" + ret + " err='" + nc4.nc_strerror(ret) + "' on\n" + v);
int varid = varidp.getValue();
vinfo.varid = varid;
if (debugWrite)
System.out.printf("added variable %s (grpid %d varid %d) %n", v.getShortName(), vinfo.g4.grpid, vinfo.varid);
if (version.isNetdf4format() && v.getRank() > 0) {
boolean isChunked = chunker.isChunked(v);
int storage = isChunked ? Nc4prototypes.NC_CHUNKED : Nc4prototypes.NC_CONTIGUOUS;
SizeT[] chunking;
if (isChunked) {
long[] lchunks = chunker.computeChunking(v);
chunking = new SizeT[lchunks.length];
for (int i = 0; i < lchunks.length; i++)
chunking[i] = new SizeT(lchunks[i]);
} else
chunking = new SizeT[v.getRank()];
ret = nc4.nc_def_var_chunking(g4.grpid, varid, storage, chunking);
if (ret != 0) {
throw new IOException(nc4.nc_strerror(ret) + " nc_def_var_chunking on variable " + v.getFullName());
}
if (isChunked) {
int deflateLevel = chunker.getDeflateLevel(v);
int deflate = deflateLevel > 0 ? 1 : 0;
int shuffle = chunker.isShuffle(v) ? 1 : 0;
if (deflateLevel > 0) {
ret = nc4.nc_def_var_deflate(g4.grpid, varid, shuffle, deflate, deflateLevel);
if (ret != 0)
throw new IOException(nc4.nc_strerror(ret));
}
}
}
v.setSPobject(vinfo);
if (v instanceof Structure) {
createCompoundMemberAtts(g4.grpid, varid, (Structure) v);
}
for (Attribute att : v.getAttributes())
writeAttribute(g4.grpid, varid, att, v);
}
/////////////////////////////////////
// compound types
/*
Compound data types can be defined for netCDF-4/HDF5 format files. A compound datatype is similar to a struct in C and contains a collection of one or more
atomic or user-defined types. The netCDF-4 compound data must comply with the properties and constraints of the HDF5 compound data type in terms of which it is implemented.
In summary these are:
It has a fixed total size.
It consists of zero or more named members that do not overlap with other members.
Each member has a name distinct from other members.
Each member has its own datatype.
Each member is referenced by an index number between zero and N-1, where N is the number of members in the compound datatype.
Each member has a fixed byte offset, which is the first byte (smallest byte address) of that member in the compound datatype.
In addition to other other user-defined data types or atomic datatypes, a member can be a small fixed-size array of any type with up to
four fixed-size dimensions (not associated with named netCDF dimensions).
Create a compound type. Provide an ncid, a name, and a total size (in bytes) of one element of the completed compound type.
After calling this function, fill out the type with repeated calls to nc_insert_compound (see nc_insert_compound).
Call nc_insert_compound once for each field you wish to insert into the compound type.
*/
private void createCompoundType(Group4 g4, Structure s) throws IOException {
IntByReference typeidp = new IntByReference();
long size = s.getElementSize();
String name = s.getShortName() + "_t";
int ret = nc4.nc_def_compound(g4.grpid, new SizeT(size), name, typeidp);
if (ret != 0)
throw new IOException(nc4.nc_strerror(ret) + " on\n" + s);
int typeid = typeidp.getValue();
if (debugCompound) System.out.printf("added compound type %s (typeid %d) size=%d %n", name, typeid, size);
List flds = new ArrayList<>();
int fldidx = 0;
long offset = 0;
for (Variable v : s.getVariables()) {
if (v.getDataType() == DataType.STRING) continue;
int field_typeid = convertDataType(v.getDataType(), v.isUnsigned());
if (v.isScalar())
ret = nc4.nc_insert_compound(g4.grpid, typeid, v.getShortName(), new SizeT(offset), field_typeid);
else
ret = nc4.nc_insert_array_compound(g4.grpid, typeid, v.getShortName(), new SizeT(offset), field_typeid, v.getRank(), v.getShape());
if (ret != 0)
throw new IOException(nc4.nc_strerror(ret) + " on\n" + s.getShortName());
Field fld = new Field(g4.grpid, typeid, fldidx, v.getShortName(), (int) offset, field_typeid, v.getRank(), v.getShape());
flds.add(fld);
if (debugCompound) System.out.printf(" added compound type member %s (%s) offset=%d size=%d%n", v.getShortName(), v.getDataType(), offset, v.getElementSize() * v.getSize());
offset += v.getElementSize() * v.getSize();
fldidx++;
}
s.setSPobject(new Vinfo(g4, -1, typeidp.getValue())); // dont know the varid yet
// keep track of the User Defined types
UserType ut = new UserType(g4.grpid, typeid, name, size, 0, (long) fldidx, NC_COMPOUND);
userTypes.put(typeid, ut);
ut.setFields(flds);
}
private void createCompoundMemberAtts(int grpid, int varid, Structure s) throws IOException {
// count size of attribute values
int sizeAtts = 0;
for (Variable m : s.getVariables()) {
for (Attribute att : m.getAttributes()) {
int elemSize;
if (att.isString()) {
String val = att.getStringValue();
elemSize = val.getBytes(CDM.UTF8).length;
if (elemSize == 0) elemSize = 1;
} else {
elemSize = att.getDataType().getSize() * att.getLength();
}
sizeAtts += elemSize;
}
}
if (sizeAtts == 0) return; // no atts; */
// create the compound type for member_atts_t
IntByReference typeidp = new IntByReference();
String typeName = "_"+s.getShortName() + "_field_atts_t";
int ret = nc4.nc_def_compound(grpid, new SizeT(sizeAtts), typeName, typeidp);
if (ret != 0)
throw new IOException(nc4.nc_strerror(ret) + " on\n" + s);
int typeid = typeidp.getValue();
if (debugCompound) System.out.printf("added compound member att type %s (typeid %d) grpid %d size=%d %n", typeName, typeid, grpid, sizeAtts); // */
// add the fields to the member_atts_t and place the values in a ByteBuffer
ByteBuffer bb = ByteBuffer.allocate(sizeAtts);
bb.order(ByteOrder.nativeOrder());
for (Variable m : s.getVariables()) {
for (Attribute att : m.getAttributes()) {
// add the fields to the member_atts_t
String memberName = m.getShortName()+":"+att.getShortName();
int field_typeid = att.isString() ? Nc4prototypes.NC_CHAR : convertDataType(att.getDataType(), att.isUnsigned()); // LOOK override String with CHAR
if (att.isString()) { // String gets turned into array of char; otherwise no way to pass in
String val = att.getStringValue();
int len = val.getBytes(CDM.UTF8).length;
if (len == 0) len = 1;
ret = nc4.nc_insert_array_compound(grpid, typeid, memberName, new SizeT(bb.position()), field_typeid, 1, new int[] {len} );
} else if (!att.isArray())
ret = nc4.nc_insert_compound(grpid, typeid, memberName, new SizeT(bb.position()), field_typeid);
else
ret = nc4.nc_insert_array_compound(grpid, typeid, memberName, new SizeT(bb.position()), field_typeid, 1, new int[] {att.getLength()} );
if (ret != 0)
throw new IOException(nc4.nc_strerror(ret) + " on\n" + s.getShortName());
if (debugCompound) {
int elemSize;
if (att.isString()) {
String val = att.getStringValue();
elemSize = val.getBytes(CDM.UTF8).length;
} else {
elemSize = att.getDataType().getSize() * att.getLength();
}
System.out.printf(" added compound att member %s type %s (%d) offset=%d elemSize=%d%n", memberName, att.getDataType(), field_typeid, bb.position(), elemSize);
}
// place the values in a ByteBuffer
if (att.isString()) {
String val = att.getStringValue();
byte[] sby = val.getBytes(CDM.UTF8);
for (byte b : sby)
bb.put(b);
if (sby.length == 0) bb.put((byte)0); // empyy string has a 0
} else {
for (int i=0; i
...
#define NDIM 2 /* rank of netCDF variable
int ncid; /* netCDF ID
int status; /* error status *
int rhid; /* variable ID *
static size_t start[NDIM] /* netCDF variable start point: *
= {0, 0}; /* first element *
static size_t count[NDIM] /* size of internal array: entire *
= {2, 3}; /* (subsampled) netCDF variable *
static ptrdiff_t stride[NDIM] /* variable subsampling intervals: *
= {2, 2}; /* access every other netCDF element *
float rh[2][3]; /* note subsampled sizes for netCDF variable dimensions LOOK [][] not [,]
...
status = nc_open("foo.nc", NC_WRITE, &ncid);
if (status != NC_NOERR) handle_error(status);
...
status = nc_inq_varid(ncid, "rh", &rhid);
if (status != NC_NOERR) handle_error(status);
...
status = nc_put_vars_float(ncid, rhid, start, count, stride, rh);
if (status != NC_NOERR) handle_error(status);
*/
private void writeCompoundData(Structure s, UserType userType, int grpid, int varid, int typeid, Section section, ArrayStructure values) throws IOException, InvalidRangeException {
SizeT[] origin = convertSizeT(section.getOrigin());
SizeT[] shape = convertSizeT(section.getShape());
SizeT[] stride = convertSizeT(section.getStride());
ArrayStructureBB valuesBB = StructureDataDeep.copyToArrayBB(s, values, ByteOrder.nativeOrder()); // LOOK embedded strings getting lost ??
ByteBuffer bbuff = valuesBB.getByteBuffer();
if (debugCompound)
System.out.printf("writeCompoundData variable %s (grpid %d varid %d) %n", s.getShortName(), grpid, varid);
// write the data
// int ret = nc4.nc_put_var(grpid, varid, bbuff);
int ret;
if(section.isStrided())
ret = nc4.nc_put_vars(grpid, varid, origin, shape, stride, bbuff.array());
else
ret = nc4.nc_put_vara(grpid, varid, origin, shape, bbuff.array());
if (ret != 0)
throw new IOException(errMessage("nc_put_vars", ret, grpid, varid));
}
@Override
public int appendStructureData(Structure s, StructureData sdata) throws IOException, InvalidRangeException {
Vinfo vinfo = (Vinfo) s.getSPobject();
Dimension dim = s.getDimension(0); // LOOK must be outer dim
int dimid = vinfo.g4.dimHash.get(dim);
SizeTByReference lenp = new SizeTByReference();
int ret = nc4.nc_inq_dimlen(vinfo.g4.grpid, dimid, lenp);
if (ret != 0)
throw new IOException(errMessage("nc_inq_dimlen", ret, vinfo.g4.grpid, dimid));
SizeT[] origin = new SizeT[]{lenp.getValue()};
SizeT[] shape = new SizeT[]{new SizeT(1)};
SizeT[] stride = new SizeT[]{new SizeT(1)};
//ArrayStructureBB valuesBB = IospHelper.copyToArrayBB(sdata, ByteOrder.nativeOrder()); // n4 wants native byte order
// ByteBuffer bbuff = valuesBB.getByteBuffer();
ByteBuffer bbuff = makeBB(s, sdata);
// write the data
//ret = nc4.nc_put_vara(vinfo.g4.grpid, vinfo.varid, origin, shape, bbuff);
//ret = nc4.nc_put_vars(vinfo.g4.grpid, vinfo.varid, origin, shape, stride, bbuff);
ret = nc4.nc_put_vars(vinfo.g4.grpid, vinfo.varid, origin, shape, stride, bbuff.array());
if (ret != 0)
throw new IOException(errMessage("appendStructureData (nc_put_vars)", ret, vinfo.g4.grpid, vinfo.varid));
return origin[0].intValue(); // recnum
}
private String errMessage(String what, int ret, int grpid, int varid) {
Formatter f = new Formatter();
f.format("%s: %d: %s grpid=%d objid=%d", what, ret, nc4.nc_strerror(ret), grpid, varid);
return f.toString();
}
// copy data out of sdata into a ByteBuffer, based on the menmbers and offsets in s
private ByteBuffer makeBB(Structure s, StructureData sdata) {
int size = s.getElementSize();
ByteBuffer bb = ByteBuffer.allocate(size);
bb.order(ByteOrder.nativeOrder());
long offset = 0;
for (Variable v : s.getVariables()) {
if (v.getDataType() == DataType.STRING) continue; // LOOK embedded strings getting lost
StructureMembers.Member m = sdata.findMember(v.getShortName());
if (m == null) {
System.out.printf("WARN Nc4Iosp.makeBB() cant find %s%n", v.getShortName());
bb.position((int) (offset + v.getElementSize()*v.getSize())); // skip over it
} else {
copy(sdata, m, bb);
}
offset += v.getElementSize() * v.getSize();
}
return bb;
}
private void copy(StructureData sdata, StructureMembers.Member m, ByteBuffer bb) {
DataType dtype = m.getDataType();
if (m.isScalar()) {
switch (dtype) {
case FLOAT:
bb.putFloat(sdata.getScalarFloat(m));
break;
case DOUBLE:
bb.putDouble(sdata.getScalarDouble(m));
break;
case INT:
case ENUM4:
bb.putInt(sdata.getScalarInt(m));
break;
case SHORT:
case ENUM2:
bb.putShort(sdata.getScalarShort(m));
break;
case BYTE:
case ENUM1:
bb.put(sdata.getScalarByte(m));
break;
case CHAR:
bb.put((byte) sdata.getScalarChar(m));
break;
case LONG:
bb.putLong(sdata.getScalarLong(m));
break;
default:
throw new IllegalStateException("scalar " + dtype.toString());
/* case BOOLEAN:
break;
case SEQUENCE:
break;
case STRUCTURE:
break;
case OPAQUE:
break; */
}
} else {
int n = m.getSize();
switch (dtype) {
case FLOAT:
float[] fdata = sdata.getJavaArrayFloat(m);
for (int i = 0; i < n; i++)
bb.putFloat(fdata[i]);
break;
case DOUBLE:
double[] ddata = sdata.getJavaArrayDouble(m);
for (int i = 0; i < n; i++)
bb.putDouble(ddata[i]);
break;
case INT:
case ENUM4:
int[] idata = sdata.getJavaArrayInt(m);
for (int i = 0; i < n; i++)
bb.putInt(idata[i]);
break;
case SHORT:
case ENUM2:
short[] shdata = sdata.getJavaArrayShort(m);
for (int i = 0; i < n; i++)
bb.putShort(shdata[i]);
break;
case BYTE:
case ENUM1:
byte[] bdata = sdata.getJavaArrayByte(m);
for (int i = 0; i < n; i++)
bb.put(bdata[i]);
break;
case CHAR:
char[] cdata = sdata.getJavaArrayChar(m);
bb.put(IospHelper.convertCharToByte(cdata));
break;
case LONG:
long[] ldata = sdata.getJavaArrayLong(m);
for (int i = 0; i < n; i++)
bb.putLong(ldata[i]);
break;
default:
throw new IllegalStateException("array " + dtype.toString());
/* case BOOLEAN:
break;
case OPAQUE:
break;
case STRUCTURE:
break; // */
case SEQUENCE:
break; // skip
}
}
}
/* private void writeDataAll(Variable v, int grpid, int varid, int typeid, Array values) throws IOException, InvalidRangeException {
Object data = values.getStorage();
boolean isUnsigned = isUnsigned(typeid);
switch (typeid) {
case Nc4prototypes.NC_BYTE:
case Nc4prototypes.NC_UBYTE:
byte[] valb = (byte[]) data;
int ret = isUnsigned ? nc4.nc_put_var_uchar(grpid, varid, valb) :
nc4.nc_put_var_schar(grpid, varid, valb);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
break;
case Nc4prototypes.NC_CHAR:
char[] valc = (char[]) data; // chars are lame
valb = IospHelper.convertCharToByte(valc);
ret = nc4.nc_put_var_text(grpid, varid, valb);
if (ret != 0) {
log.error("{} on var {}", nc4.nc_strerror(ret), v);
return;
//throw new IOException(nc4.nc_strerror(ret));
}
break;
case Nc4prototypes.NC_DOUBLE:
double[] vald = (double[]) data;
ret = nc4.nc_put_var_double(grpid, varid, vald);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
break;
case Nc4prototypes.NC_FLOAT:
float[] valf = (float[]) data;
ret = nc4.nc_put_var_float(grpid, varid, valf);
if (ret != 0) {
log.error("{} on var {}", nc4.nc_strerror(ret), v);
return;
//throw new IOException(nc4.nc_strerror(ret));
}
break;
case Nc4prototypes.NC_INT:
int[] vali = (int[]) data;
ret = isUnsigned ? nc4.nc_put_var_uint(grpid, varid, vali) :
nc4.nc_put_var_int(grpid, varid, vali);
if (ret != 0) {
log.error("{} on var {}", nc4.nc_strerror(ret), v);
return;
//throw new IOException(nc4.nc_strerror(ret));
}
break;
case Nc4prototypes.NC_INT64:
long[] vall = (long[]) data;
ret = isUnsigned ? nc4.nc_put_var_ulonglong(grpid, varid, vall) :
nc4.nc_put_var_longlong(grpid, varid, vall);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
break;
case Nc4prototypes.NC_SHORT:
short[] vals = (short[]) data;
ret = isUnsigned ? nc4.nc_put_var_ushort(grpid, varid, vals) :
nc4.nc_put_var_short(grpid, varid, vals);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
break;
case Nc4prototypes.NC_STRING:
String[] valss = convertStringData(data);
ret = nc4.nc_put_var_string(grpid, varid, valss);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
break;
default:
UserType userType = userTypes.get(typeid);
if (userType == null) {
throw new IOException("Unknown userType == " + typeid);
} else if (userType.typeClass == Nc4prototypes.NC_ENUM) {
//return readDataSection(grpid, varid, userType.baseTypeid, section);
} else if (userType.typeClass == Nc4prototypes.NC_VLEN) { // cannot subset
//return readVlen(grpid, varid, len, userType);
} else if (userType.typeClass == Nc4prototypes.NC_OPAQUE) {
//return readOpaque(grpid, varid, section, userType.size);
} else if (userType.typeClass == Nc4prototypes.NC_COMPOUND) {
//return readCompound(grpid, varid, section, userType);
}
throw new IOException("Unsupported userType = " + typeid + " userType= " + userType);
}
// System.out.printf("OK var %s%n", v);
} */
private String[] convertStringData(Object org) throws IOException {
if (org instanceof String[]) return (String[]) org;
if (org instanceof Object[]) {
Object[] oo = (Object[]) org;
String[] result = new String[oo.length];
int count = 0;
for (Object s : oo)
result[count++] = (String) s;
return result;
}
throw new IOException("convertStringData failed on class = " + org.getClass().getName());
}
/////////////////////////////////////////////////////////////////////////
@Override
public void flush() throws IOException {
int ret = nc4.nc_sync(ncid);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
// reread dimension in case unlimited has grown
updateDimensions(ncfile.getRootGroup());
}
@Override
public void setFill(boolean fill) {
this.fill = fill;
try {
_setFill();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void _setFill() throws IOException {
if (nc4 == null || ncid < 0) return; // not open yet
IntByReference old_modep = new IntByReference();
int ret = nc4.nc_set_fill(ncid, fill ? Nc4prototypes.NC_FILL : Nc4prototypes.NC_NOFILL, old_modep);
if (ret != 0)
throw new IOException(ret + ": " + nc4.nc_strerror(ret));
}
@Override
public boolean rewriteHeader(boolean largeFile) throws IOException {
return false;
}
@Override
public void updateAttribute(Variable v2, Attribute att) throws IOException {
if (v2 == null)
writeAttribute(ncid, Nc4prototypes.NC_GLOBAL, att, null);
else {
Vinfo vinfo = (Vinfo) v2.getSPobject();
writeAttribute(vinfo.g4.grpid, vinfo.varid, att, v2);
}
}
static public long
getNativeAddr(int pos, ByteBuffer buf)
{
return (NativeLong.SIZE == (Integer.SIZE/8) ? buf.getInt(pos) : buf.getLong(pos));
}
}