    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 files COPYING and Copyright.html. *
    009 * COPYING can be found at the root of the source code distribution tree.    *
    010 * Or, see https://support.hdfgroup.org/products/licenses.html               *
    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 * <p>
    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     * <p>
    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     * <p>
    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.DataFormat#hasAttribute()
    105     */
    106    @Override
    107    public boolean hasAttribute() {
    108        return false;
    109    }
    110
    111    /*
    112     * (non-Javadoc)
    113     *
    114     * @see hdf.object.Datatype#fromNative(long)
    115     */
    116    @Override
    117    public void fromNative(long tid)
    118    {
    119        datatypeOrder = NATIVE;
    120        datatypeSign = NATIVE;
    121
    122        switch ((int) tid) {
    123            case HDFConstants.DFNT_CHAR:
    124                datatypeClass = CLASS_CHAR;
    125                datatypeSize = 1;
    126                break;
    127            case HDFConstants.DFNT_UCHAR8:
    128                datatypeClass = CLASS_CHAR;
    129                datatypeSize = 1;
    130                datatypeSign = SIGN_NONE;
    131                break;
    132            case HDFConstants.DFNT_INT8:
    133                datatypeClass = CLASS_INTEGER;
    134                datatypeSize = 1;
    135                break;
    136            case HDFConstants.DFNT_UINT8:
    137                datatypeClass = CLASS_INTEGER;
    138                datatypeSize = 1;
    139                datatypeSign = SIGN_NONE;
    140                break;
    141            case HDFConstants.DFNT_INT16:
    142                datatypeClass = CLASS_INTEGER;
    143                datatypeSize = 2;
    144                break;
    145            case HDFConstants.DFNT_UINT16:
    146                datatypeClass = CLASS_INTEGER;
    147                datatypeSize = 2;
    148                datatypeSign = SIGN_NONE;
    149                break;
    150            case HDFConstants.DFNT_INT32:
    151                datatypeClass = CLASS_INTEGER;
    152                datatypeSize = 4;
    153                break;
    154            case HDFConstants.DFNT_UINT32:
    155                datatypeClass = CLASS_INTEGER;
    156                datatypeSize = 4;
    157                datatypeSign = SIGN_NONE;
    158                break;
    159            case HDFConstants.DFNT_INT64:
    160                datatypeClass = CLASS_INTEGER;
    161                datatypeSize = 8;
    162                break;
    163            case HDFConstants.DFNT_UINT64:
    164                datatypeClass = CLASS_INTEGER;
    165                datatypeSize = 8;
    166                datatypeSign = SIGN_NONE;
    167                break;
    168            case HDFConstants.DFNT_FLOAT32:
    169                datatypeClass = CLASS_FLOAT;
    170                datatypeSize = 4;
    171                break;
    172            case HDFConstants.DFNT_FLOAT64:
    173                datatypeClass = CLASS_FLOAT;
    174                datatypeSize = 8;
    175                break;
    176            default:
    177                datatypeClass = CLASS_NO_CLASS;
    178                break;
    179        }
    180
    181        log.trace("Datatype class={} size={}", datatypeClass, datatypeSize);
    182    }
    183
    184    /**
    185     * Allocate a 1D array large enough to hold a multidimensional array of 'datasize' elements of
    186     * 'datatype' numbers.
    187     *
    188     * @param datatype
    189     *            the data type
    190     * @param datasize
    191     *            the size of the data array
    192     *
    193     * @return an array of 'datasize' numbers of datatype.
    194     *
    195     * @throws OutOfMemoryError
    196     *             if the array cannot be allocated
    197     */
    198    public static final Object allocateArray(long datatype, int datasize)
    199            throws OutOfMemoryError {
    200        if (datasize <= 0) {
    201            log.debug("datasize <= 0");
    202            return null;
    203        }
    204
    205        Object data = null;
    206
    207        switch ((int) datatype) {
    208            case HDFConstants.DFNT_CHAR:
    209            case HDFConstants.DFNT_UCHAR8:
    210            case HDFConstants.DFNT_UINT8:
    211            case HDFConstants.DFNT_INT8:
    212                log.trace("allocateArray(): allocating byte array of size {}", datasize);
    213                data = new byte[datasize];
    214                break;
    215            case HDFConstants.DFNT_INT16:
    216            case HDFConstants.DFNT_UINT16:
    217                log.trace("allocateArray(): allocating short array of size {}", datasize);
    218                data = new short[datasize];
    219                break;
    220            case HDFConstants.DFNT_INT32:
    221            case HDFConstants.DFNT_UINT32:
    222                log.trace("allocateArray(): allocating int array of size {}", datasize);
    223                data = new int[datasize];
    224                break;
    225            case HDFConstants.DFNT_INT64:
    226            case HDFConstants.DFNT_UINT64:
    227                log.trace("allocateArray(): allocating long array of size {}", datasize);
    228                data = new long[datasize];
    229                break;
    230            case HDFConstants.DFNT_FLOAT32:
    231                log.trace("allocateArray(): allocating float array of size {}", datasize);
    232                data = new float[datasize];
    233                break;
    234            case HDFConstants.DFNT_FLOAT64:
    235                log.trace("allocateArray(): allocating double array of size {}", datasize);
    236                data = new double[datasize];
    237                break;
    238            default:
    239                log.debug("allocateArray(): unknown datatype {}", datatype);
    240                data = null;
    241                break;
    242        }
    243
    244        return data;
    245    }
    246
    247    /*
    248     * (non-Javadoc)
    249     *
    250     * @see hdf.object.Datatype#getDatatypeDescription()
    251     */
    252    @Override
    253    public String getDescription() {
    254
    255        if (datatypeDescription != null) {
    256            return datatypeDescription;
    257        }
    258
    259        String description = null;
    260
    261        switch (datatypeClass) {
    262            case CLASS_CHAR:
    263                description = "8-bit " + (isUnsigned() ? "unsigned " : "") + "character";
    264                break;
    265            case CLASS_INTEGER:
    266                description = String.valueOf(datatypeSize * 8) + "-bit " + (isUnsigned() ? "unsigned " : "") + "integer";
    267                break;
    268            case CLASS_FLOAT:
    269                description = String.valueOf(datatypeSize * 8) + "-bit floating-point";
    270                break;
    271            default:
    272                description = "Unknown";
    273                break;
    274        }
    275
    276        return description;
    277    }
    278
    279    /*
    280     * (non-Javadoc)
    281     *
    282     * @see hdf.object.Datatype#isUnsigned()
    283     */
    284    @Override
    285    public boolean isUnsigned() {
    286        return (Datatype.SIGN_NONE == getDatatypeSign());
    287    }
    288
    289    /**
    290     * Checks if the datatype is an unsigned integer.
    291     *
    292     * @param datatype
    293     *            the data type.
    294     *
    295     * @return True is the datatype is an unsigned integer; otherwise returns false.
    296     */
    297    public static final boolean isUnsigned(long datatype) {
    298        boolean unsigned = false;
    299
    300        switch((int) datatype) {
    301            case HDFConstants.DFNT_UCHAR8:
    302            case HDFConstants.DFNT_UINT8:
    303            case HDFConstants.DFNT_UINT16:
    304            case HDFConstants.DFNT_UINT32:
    305            case HDFConstants.DFNT_UINT64:
    306                unsigned = true;
    307                break;
    308            default:
    309                log.debug("isUnsigned(): unknown datatype {}", datatype);
    310                unsigned = false;
    311                break;
    312        }
    313
    314        return unsigned;
    315    }
    316
    317    @Override
    318    public boolean isText() {
    319        return (Datatype.CLASS_STRING == getDatatypeClass());
    320    }
    321
    322    /*
    323     * (non-Javadoc)
    324     * @see hdf.object.Datatype#createNative()
    325     */
    326    @Override
    327    public long createNative()
    328    {
    329        long tid = -1;
    330        int tclass = getDatatypeClass();
    331        int tsize = (int) getDatatypeSize();
    332
    333        // figure the datatype
    334        switch (tclass) {
    335            case Datatype.CLASS_INTEGER:
    336                if (tsize == 1) {
    337                    if (isUnsigned()) {
    338                        tid = HDFConstants.DFNT_UINT8;
    339                    }
    340                    else {
    341                        tid = HDFConstants.DFNT_INT8;
    342                    }
    343                }
    344                else if (tsize == 2) {
    345                    if (isUnsigned()) {
    346                        tid = HDFConstants.DFNT_UINT16;
    347                    }
    348                    else {
    349                        tid = HDFConstants.DFNT_INT16;
    350                    }
    351                }
    352                else if ((tsize == 4) || (tsize == NATIVE)) {
    353                    if (isUnsigned()) {
    354                        tid = HDFConstants.DFNT_UINT32;
    355                    }
    356                    else {
    357                        tid = HDFConstants.DFNT_INT32;
    358                    }
    359                }
    360                else if (tsize == 8) {
    361                    if (isUnsigned()) {
    362                        tid = HDFConstants.DFNT_UINT64;
    363                    }
    364                    else {
    365                        tid = HDFConstants.DFNT_INT64;
    366                    }
    367                }
    368                break;
    369            case Datatype.CLASS_FLOAT:
    370                if (tsize == Datatype.NATIVE) {
    371                    tid = HDFConstants.DFNT_FLOAT;
    372                }
    373                else if (tsize == 4) {
    374                    tid = HDFConstants.DFNT_FLOAT32;
    375                }
    376                else if (tsize == 8) {
    377                    tid = HDFConstants.DFNT_FLOAT64;
    378                }
    379                break;
    380            case Datatype.CLASS_CHAR:
    381                if (isUnsigned()) {
    382                    tid = HDFConstants.DFNT_UCHAR;
    383                }
    384                else {
    385                    tid = HDFConstants.DFNT_CHAR;
    386                }
    387                break;
    388            case Datatype.CLASS_STRING:
    389                tid = HDFConstants.DFNT_CHAR;
    390                break;
    391            default:
    392                log.debug("createNative(): unknown datatype class {}", tclass);
    393        }
    394
    395        return tid;
    396    }
    397
    398    /*
    399     * (non-Javadoc)
    400     *
    401     * @see hdf.object.Datatype#close(int)
    402     */
    403    @Override
    404    public void close(long id) {
    405        // No implementation
    406    }
    407
    408    // Implementing DataFormat
    409    @SuppressWarnings("rawtypes")
    410    public List getMetadata(int... attrPropList) throws Exception {
    411        throw new UnsupportedOperationException("getMetadata(int... attrPropList) is not supported");
    412    }
    413}