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 *
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}