    001/*****************************************************************************
    002 * Copyright by The HDF Group.                                               *
    003 * Copyright by the Board of Trustees of the University of Illinois.         *
    004 * All rights reserved.                                                      *
    005 *                                                                           *
    006 * This file is part of the HDF Java Products distribution.                  *
    007 * The full copyright notice, including terms governing use, modification,   *
    008 * and redistribution, is contained in the COPYING file, which can be found  *
    009 * at the root of the source code distribution tree,                         *
    010 * or in https://www.hdfgroup.org/licenses.                                  *
    011 * If you do not have access to either file, you may request a copy from     *
    012 * help@hdfgroup.org.                                                        *
    013 ****************************************************************************/
    014
    015package hdf.object.h4;
    016
    017import java.util.List;
    018
    019import hdf.hdflib.HDFConstants;
    020import hdf.object.Datatype;
    021
    022/**
    023 * This class defines HDF4 data type characteristics and APIs for a data type.
    024 *
    025 * This class provides several methods to convert an HDF4 datatype identifier to a datatype object,
    026 * and vice versa. A datatype object is described by four basic fields: datatype class, size, byte
    027 * order, and sign, while an HDF5 datatype is presented by a datatype identifier.
    028 *
    029 * @version 1.1 9/4/2007
    030 * @author Peter X. Cao
    031 */
    032public class H4Datatype extends Datatype {
    033    private static final long serialVersionUID = -1342029403385521874L;
    034
    035    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(H4Datatype.class);
    036
    037    /**
    038     * Constructs a H4Datatype with specified class, size, byte order and sign.
    039     *
    040     * The following is a list of a few examples of H4Datatype:
    041     * <ol>
    042     * <li>to create unsigned native integer<br>
    043     * H4Datatype type = new H4Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE);
    044     * <li>to create 16-bit signed integer with big endian<br>
    045     * H4Datatype type = new H4Dataype(Datatype.CLASS_INTEGER, 2, Datatype.ORDER_BE, Datatype.NATIVE);
    046     * <li>to create native float<br>
    047     * H4Datatype type = new H4Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE);
    048     * <li>to create 64-bit double<br>
    049     * H4Datatype type = new H4Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE);
    050     * </ol>
    051     *
    052     * @param tclass
    053     *            the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
    054     * @param tsize
    055     *            the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4.
    056     *            Valid values are NATIVE or a positive value.
    057     * @param torder
    058     *            the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX,
    059     *            ORDER_NONE and NATIVE.
    060     * @param tsign
    061     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE.
    062     *
    063     * @throws Exception
    064     *            if there is an error
    065     */
    066    public H4Datatype(int tclass, int tsize, int torder, int tsign) throws Exception {
    067        super(tclass, tsize, torder, tsign);
    068        datatypeDescription = getDescription();
    069    }
    070
    071    /**
    072     * Constructs a H4Datatype with a given native datatype identifier.
    073     *
    074     * For example,
    075     *
    076     * <pre>
    077     * Datatype dtype = new H4Datatype(HDFConstants.DFNT_INT32);
    078     * </pre>
    079     *
    080     * will construct a datatype equivalent to
    081     *
    082     * <pre>
    083     * new H4Datatype(Datatype.CLASS_INTEGER, 4, Datatype.NATIVE, Datatype.SIGN_NONE);
    084     * </pre>
    085     *
    086     * @see #fromNative(long nativeID)
    087     *
    088     * @param nativeID
    089     *            the native datatype identifier.
    090     *
    091     * @throws Exception
    092     *            if there is an error
    093     */
    094    public H4Datatype(long nativeID) throws Exception {
    095        super(null, nativeID);
    096
    097        fromNative(nativeID);
    098        datatypeDescription = getDescription();
    099    }
    100
    101    /*
    102     * (non-Javadoc)
    103     *
    104     * @see hdf.object.Datatype#fromNative(long)
    105     */
    106    @Override
    107    public void fromNative(long tid) {
    108        datatypeOrder = NATIVE;
    109        datatypeSign = NATIVE;
    110
    111        switch ((int) tid) {
    112            case HDFConstants.DFNT_CHAR:
    113                datatypeClass = CLASS_CHAR;
    114                datatypeSize = 1;
    115                break;
    116            case HDFConstants.DFNT_UCHAR8:
    117                datatypeClass = CLASS_CHAR;
    118                datatypeSize = 1;
    119                datatypeSign = SIGN_NONE;
    120                break;
    121            case HDFConstants.DFNT_INT8:
    122                datatypeClass = CLASS_INTEGER;
    123                datatypeSize = 1;
    124                break;
    125            case HDFConstants.DFNT_UINT8:
    126                datatypeClass = CLASS_INTEGER;
    127                datatypeSize = 1;
    128                datatypeSign = SIGN_NONE;
    129                break;
    130            case HDFConstants.DFNT_INT16:
    131                datatypeClass = CLASS_INTEGER;
    132                datatypeSize = 2;
    133                break;
    134            case HDFConstants.DFNT_UINT16:
    135                datatypeClass = CLASS_INTEGER;
    136                datatypeSize = 2;
    137                datatypeSign = SIGN_NONE;
    138                break;
    139            case HDFConstants.DFNT_INT32:
    140                datatypeClass = CLASS_INTEGER;
    141                datatypeSize = 4;
    142                break;
    143            case HDFConstants.DFNT_UINT32:
    144                datatypeClass = CLASS_INTEGER;
    145                datatypeSize = 4;
    146                datatypeSign = SIGN_NONE;
    147                break;
    148            case HDFConstants.DFNT_INT64:
    149                datatypeClass = CLASS_INTEGER;
    150                datatypeSize = 8;
    151                break;
    152            case HDFConstants.DFNT_UINT64:
    153                datatypeClass = CLASS_INTEGER;
    154                datatypeSize = 8;
    155                datatypeSign = SIGN_NONE;
    156                break;
    157            case HDFConstants.DFNT_FLOAT32:
    158                datatypeClass = CLASS_FLOAT;
    159                datatypeSize = 4;
    160                break;
    161            case HDFConstants.DFNT_FLOAT64:
    162                datatypeClass = CLASS_FLOAT;
    163                datatypeSize = 8;
    164                break;
    165            default:
    166                datatypeClass = CLASS_NO_CLASS;
    167                break;
    168        }
    169
    170        log.trace("Datatype class={} size={}", datatypeClass, datatypeSize);
    171    }
    172
    173    /**
    174     * Allocate a 1D array large enough to hold a multidimensional array of 'datasize' elements of
    175     * 'datatype' numbers.
    176     *
    177     * @param datatype
    178     *            the data type
    179     * @param datasize
    180     *            the size of the data array
    181     *
    182     * @return an array of 'datasize' numbers of datatype.
    183     *
    184     * @throws OutOfMemoryError
    185     *             if the array cannot be allocated
    186     */
    187    public static final Object allocateArray(long datatype, int datasize) throws OutOfMemoryError {
    188        if (datasize <= 0) {
    189            log.debug("datasize <= 0");
    190            return null;
    191        }
    192
    193        Object data = null;
    194
    195        switch ((int) datatype) {
    196            case HDFConstants.DFNT_CHAR:
    197            case HDFConstants.DFNT_UCHAR8:
    198            case HDFConstants.DFNT_UINT8:
    199            case HDFConstants.DFNT_INT8:
    200                log.trace("allocateArray(): allocating byte array of size {}", datasize);
    201                data = new byte[datasize];
    202                break;
    203            case HDFConstants.DFNT_INT16:
    204            case HDFConstants.DFNT_UINT16:
    205                log.trace("allocateArray(): allocating short array of size {}", datasize);
    206                data = new short[datasize];
    207                break;
    208            case HDFConstants.DFNT_INT32:
    209            case HDFConstants.DFNT_UINT32:
    210                log.trace("allocateArray(): allocating int array of size {}", datasize);
    211                if (datasize == NATIVE)
    212                    datasize = 4;
    213                data = new int[datasize];
    214                break;
    215            case HDFConstants.DFNT_INT64:
    216            case HDFConstants.DFNT_UINT64:
    217                log.trace("allocateArray(): allocating long array of size {}", datasize);
    218                data = new long[datasize];
    219                break;
    220            case HDFConstants.DFNT_FLOAT32:
    221                log.trace("allocateArray(): allocating float array of size {}", datasize);
    222                data = new float[datasize];
    223                break;
    224            case HDFConstants.DFNT_FLOAT64:
    225                log.trace("allocateArray(): allocating double array of size {}", datasize);
    226                data = new double[datasize];
    227                break;
    228            default:
    229                log.debug("allocateArray(): unknown datatype {}", datatype);
    230                data = null;
    231                break;
    232        }
    233
    234        return data;
    235    }
    236
    237    /*
    238     * (non-Javadoc)
    239     *
    240     * @see hdf.object.Datatype#getDatatypeDescription()
    241     */
    242    @Override
    243    public String getDescription() {
    244        if (datatypeDescription != null)
    245            return datatypeDescription;
    246
    247        String description = null;
    248
    249        switch (datatypeClass) {
    250            case CLASS_CHAR:
    251                description = "8-bit " + (isUnsigned() ? "unsigned " : "") + "character";
    252                break;
    253            case CLASS_INTEGER:
    254                description = String.valueOf(datatypeSize * 8) + "-bit " + (isUnsigned() ? "unsigned " : "") + "integer";
    255                break;
    256            case CLASS_FLOAT:
    257                description = String.valueOf(datatypeSize * 8) + "-bit floating-point";
    258                break;
    259            default:
    260                description = "Unknown";
    261                break;
    262        }
    263
    264        return description;
    265    }
    266
    267    /*
    268     * (non-Javadoc)
    269     *
    270     * @see hdf.object.Datatype#isUnsigned()
    271     */
    272    @Override
    273    public boolean isUnsigned() {
    274        return (Datatype.SIGN_NONE == getDatatypeSign());
    275    }
    276
    277    /**
    278     * Checks if the datatype is an unsigned integer.
    279     *
    280     * @param datatype
    281     *            the data type.
    282     *
    283     * @return True is the datatype is an unsigned integer; otherwise returns false.
    284     */
    285    public static final boolean isUnsigned(long datatype) {
    286        boolean unsigned = false;
    287
    288        switch((int) datatype) {
    289            case HDFConstants.DFNT_UCHAR8:
    290            case HDFConstants.DFNT_UINT8:
    291            case HDFConstants.DFNT_UINT16:
    292            case HDFConstants.DFNT_UINT32:
    293            case HDFConstants.DFNT_UINT64:
    294                unsigned = true;
    295                break;
    296            default:
    297                log.debug("isUnsigned(): unknown datatype {}", datatype);
    298                unsigned = false;
    299                break;
    300        }
    301
    302        return unsigned;
    303    }
    304
    305    @Override
    306    public boolean isText() {
    307        return (Datatype.CLASS_STRING == getDatatypeClass());
    308    }
    309
    310    /*
    311     * (non-Javadoc)
    312     * @see hdf.object.Datatype#createNative()
    313     */
    314    @Override
    315    public long createNative() {
    316        long tid = -1;
    317        int tclass = getDatatypeClass();
    318        int tsize = (int) getDatatypeSize();
    319
    320        // figure the datatype
    321        switch (tclass) {
    322            case Datatype.CLASS_INTEGER:
    323                if (tsize == 1) {
    324                    if (isUnsigned()) {
    325                        tid = HDFConstants.DFNT_UINT8;
    326                    }
    327                    else {
    328                        tid = HDFConstants.DFNT_INT8;
    329                    }
    330                }
    331                else if (tsize == 2) {
    332                    if (isUnsigned()) {
    333                        tid = HDFConstants.DFNT_UINT16;
    334                    }
    335                    else {
    336                        tid = HDFConstants.DFNT_INT16;
    337                    }
    338                }
    339                else if ((tsize == 4) || (tsize == NATIVE)) {
    340                    if (isUnsigned()) {
    341                        tid = HDFConstants.DFNT_UINT32;
    342                    }
    343                    else {
    344                        tid = HDFConstants.DFNT_INT32;
    345                    }
    346                }
    347                else if (tsize == 8) {
    348                    if (isUnsigned()) {
    349                        tid = HDFConstants.DFNT_UINT64;
    350                    }
    351                    else {
    352                        tid = HDFConstants.DFNT_INT64;
    353                    }
    354                }
    355                break;
    356            case Datatype.CLASS_FLOAT:
    357                if (tsize == Datatype.NATIVE) {
    358                    tid = HDFConstants.DFNT_FLOAT;
    359                }
    360                else if (tsize == 4) {
    361                    tid = HDFConstants.DFNT_FLOAT32;
    362                }
    363                else if (tsize == 8) {
    364                    tid = HDFConstants.DFNT_FLOAT64;
    365                }
    366                break;
    367            case Datatype.CLASS_CHAR:
    368                if (isUnsigned()) {
    369                    tid = HDFConstants.DFNT_UCHAR;
    370                }
    371                else {
    372                    tid = HDFConstants.DFNT_CHAR;
    373                }
    374                break;
    375            case Datatype.CLASS_STRING:
    376                tid = HDFConstants.DFNT_CHAR;
    377                break;
    378            default:
    379                log.debug("createNative(): unknown datatype class {}", tclass);
    380        }
    381
    382        return tid;
    383    }
    384
    385    /*
    386     * (non-Javadoc)
    387     *
    388     * @see hdf.object.Datatype#close(int)
    389     */
    390    @Override
    391    public void close(long id) {
    392        // No implementation
    393    }
    394
    395    // Implementing MetaDataContainer
    396    /**
    397     * Retrieves the object's metadata, such as attributes, from the file.
    398     *
    399     * Metadata, such as attributes, is stored in a List.
    400     *
    401     * @param attrPropList
    402     *             the list of properties to get
    403     *
    404     * @return the list of metadata objects.
    405     *
    406     * @throws Exception
    407     *             if the metadata can not be retrieved
    408     */
    409    @SuppressWarnings("rawtypes")
    410    public List getMetadata(int... attrPropList) throws Exception {
    411        throw new UnsupportedOperationException("getMetadata(int... attrPropList) is not supported");
    412    }
    413
    414    /**
    415     * Check if the object has any attributes attached.
    416     *
    417     * @return true if it has any attributes, false otherwise.
    418     */
    419    @Override
    420    public boolean hasAttribute() {
    421        return false;
    422    }
    423}