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,
044     * Datatype.SIGN_NONE); <li>to create 16-bit signed integer with big endian<br> H4Datatype type = new
045     * H4Dataype(Datatype.CLASS_INTEGER, 2, Datatype.ORDER_BE, Datatype.NATIVE); <li>to create native
046     * float<br> H4Datatype type = new H4Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE,
047     * Datatype.NATIVE); <li>to create 64-bit double<br> H4Datatype type = new H4Dataype(Datatype.CLASS_FLOAT,
048     * 8, Datatype.NATIVE, Datatype.NATIVE);
049     * </ol>
050     *
051     * @param tclass
052     *            the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
053     * @param tsize
054     *            the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4.
055     *            Valid values are NATIVE or a positive value.
056     * @param torder
057     *            the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX,
058     *            ORDER_NONE and NATIVE.
059     * @param tsign
060     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE.
061     *
062     * @throws Exception
063     *            if there is an error
064     */
065    public H4Datatype(int tclass, int tsize, int torder, int tsign) throws Exception
066    {
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    {
096        super(null, nativeID);
097
098        fromNative(nativeID);
099        datatypeDescription = getDescription();
100    }
101
102    /*
103     * (non-Javadoc)
104     *
105     * @see hdf.object.Datatype#fromNative(long)
106     */
107    @Override
108    public void fromNative(long tid)
109    {
110        datatypeOrder = NATIVE;
111        datatypeSign  = NATIVE;
112
113        switch ((int)tid) {
114        case HDFConstants.DFNT_CHAR:
115            datatypeClass = CLASS_CHAR;
116            datatypeSize  = 1;
117            break;
118        case HDFConstants.DFNT_UCHAR8:
119            datatypeClass = CLASS_CHAR;
120            datatypeSize  = 1;
121            datatypeSign  = SIGN_NONE;
122            break;
123        case HDFConstants.DFNT_INT8:
124            datatypeClass = CLASS_INTEGER;
125            datatypeSize  = 1;
126            break;
127        case HDFConstants.DFNT_UINT8:
128            datatypeClass = CLASS_INTEGER;
129            datatypeSize  = 1;
130            datatypeSign  = SIGN_NONE;
131            break;
132        case HDFConstants.DFNT_INT16:
133            datatypeClass = CLASS_INTEGER;
134            datatypeSize  = 2;
135            break;
136        case HDFConstants.DFNT_UINT16:
137            datatypeClass = CLASS_INTEGER;
138            datatypeSize  = 2;
139            datatypeSign  = SIGN_NONE;
140            break;
141        case HDFConstants.DFNT_INT32:
142            datatypeClass = CLASS_INTEGER;
143            datatypeSize  = 4;
144            break;
145        case HDFConstants.DFNT_UINT32:
146            datatypeClass = CLASS_INTEGER;
147            datatypeSize  = 4;
148            datatypeSign  = SIGN_NONE;
149            break;
150        case HDFConstants.DFNT_INT64:
151            datatypeClass = CLASS_INTEGER;
152            datatypeSize  = 8;
153            break;
154        case HDFConstants.DFNT_UINT64:
155            datatypeClass = CLASS_INTEGER;
156            datatypeSize  = 8;
157            datatypeSign  = SIGN_NONE;
158            break;
159        case HDFConstants.DFNT_FLOAT32:
160            datatypeClass = CLASS_FLOAT;
161            datatypeSize  = 4;
162            break;
163        case HDFConstants.DFNT_FLOAT64:
164            datatypeClass = CLASS_FLOAT;
165            datatypeSize  = 8;
166            break;
167        default:
168            datatypeClass = CLASS_NO_CLASS;
169            break;
170        }
171
172        log.trace("Datatype class={} size={}", datatypeClass, datatypeSize);
173    }
174
175    /**
176     * Allocate a 1D array large enough to hold a multidimensional array of 'datasize' elements of
177     * 'datatype' numbers.
178     *
179     * @param datatype
180     *            the data type
181     * @param datasize
182     *            the size of the data array
183     *
184     * @return an array of 'datasize' numbers of datatype.
185     *
186     * @throws OutOfMemoryError
187     *             if the array cannot be allocated
188     */
189    public static final Object allocateArray(long datatype, int datasize) throws OutOfMemoryError
190    {
191        if (datasize <= 0) {
192            log.debug("datasize <= 0");
193            return null;
194        }
195
196        Object data = null;
197
198        switch ((int)datatype) {
199        case HDFConstants.DFNT_CHAR:
200        case HDFConstants.DFNT_UCHAR8:
201        case HDFConstants.DFNT_UINT8:
202        case HDFConstants.DFNT_INT8:
203            log.trace("allocateArray(): allocating byte array of size {}", datasize);
204            data = new byte[datasize];
205            break;
206        case HDFConstants.DFNT_INT16:
207        case HDFConstants.DFNT_UINT16:
208            log.trace("allocateArray(): allocating short array of size {}", datasize);
209            data = new short[datasize];
210            break;
211        case HDFConstants.DFNT_INT32:
212        case HDFConstants.DFNT_UINT32:
213            log.trace("allocateArray(): allocating int array of size {}", datasize);
214            if (datasize == NATIVE)
215                datasize = 4;
216            data = new int[datasize];
217            break;
218        case HDFConstants.DFNT_INT64:
219        case HDFConstants.DFNT_UINT64:
220            log.trace("allocateArray(): allocating long array of size {}", datasize);
221            data = new long[datasize];
222            break;
223        case HDFConstants.DFNT_FLOAT32:
224            log.trace("allocateArray(): allocating float array of size {}", datasize);
225            data = new float[datasize];
226            break;
227        case HDFConstants.DFNT_FLOAT64:
228            log.trace("allocateArray(): allocating double array of size {}", datasize);
229            data = new double[datasize];
230            break;
231        default:
232            log.debug("allocateArray(): unknown datatype {}", datatype);
233            data = null;
234            break;
235        }
236
237        return data;
238    }
239
240    /*
241     * (non-Javadoc)
242     *
243     * @see hdf.object.Datatype#getDatatypeDescription()
244     */
245    @Override
246    public String getDescription()
247    {
248        if (datatypeDescription != null)
249            return datatypeDescription;
250
251        String description = null;
252
253        switch (datatypeClass) {
254        case CLASS_CHAR:
255            description = "8-bit " + (isUnsigned() ? "unsigned " : "") + "character";
256            break;
257        case CLASS_INTEGER:
258            description =
259                String.valueOf(datatypeSize * 8) + "-bit " + (isUnsigned() ? "unsigned " : "") + "integer";
260            break;
261        case CLASS_FLOAT:
262            description = String.valueOf(datatypeSize * 8) + "-bit floating-point";
263            break;
264        default:
265            description = "Unknown";
266            break;
267        }
268
269        return description;
270    }
271
272    /*
273     * (non-Javadoc)
274     *
275     * @see hdf.object.Datatype#isUnsigned()
276     */
277    @Override
278    public boolean isUnsigned()
279    {
280        return (Datatype.SIGN_NONE == getDatatypeSign());
281    }
282
283    /**
284     * Checks if the datatype is an unsigned integer.
285     *
286     * @param datatype
287     *            the data type.
288     *
289     * @return True is the datatype is an unsigned integer; otherwise returns false.
290     */
291    public static final boolean isUnsigned(long datatype)
292    {
293        boolean unsigned = false;
294
295        switch ((int)datatype) {
296        case HDFConstants.DFNT_UCHAR8:
297        case HDFConstants.DFNT_UINT8:
298        case HDFConstants.DFNT_UINT16:
299        case HDFConstants.DFNT_UINT32:
300        case HDFConstants.DFNT_UINT64:
301            unsigned = true;
302            break;
303        default:
304            log.debug("isUnsigned(): unknown datatype {}", datatype);
305            unsigned = false;
306            break;
307        }
308
309        return unsigned;
310    }
311
312    @Override
313    public boolean isText()
314    {
315        return (Datatype.CLASS_STRING == getDatatypeClass());
316    }
317
318    /*
319     * (non-Javadoc)
320     * @see hdf.object.Datatype#createNative()
321     */
322    @Override
323    public long createNative()
324    {
325        long tid   = -1;
326        int tclass = getDatatypeClass();
327        int tsize  = (int)getDatatypeSize();
328
329        // figure the datatype
330        switch (tclass) {
331        case Datatype.CLASS_INTEGER:
332            if (tsize == 1) {
333                if (isUnsigned()) {
334                    tid = HDFConstants.DFNT_UINT8;
335                }
336                else {
337                    tid = HDFConstants.DFNT_INT8;
338                }
339            }
340            else if (tsize == 2) {
341                if (isUnsigned()) {
342                    tid = HDFConstants.DFNT_UINT16;
343                }
344                else {
345                    tid = HDFConstants.DFNT_INT16;
346                }
347            }
348            else if ((tsize == 4) || (tsize == NATIVE)) {
349                if (isUnsigned()) {
350                    tid = HDFConstants.DFNT_UINT32;
351                }
352                else {
353                    tid = HDFConstants.DFNT_INT32;
354                }
355            }
356            else if (tsize == 8) {
357                if (isUnsigned()) {
358                    tid = HDFConstants.DFNT_UINT64;
359                }
360                else {
361                    tid = HDFConstants.DFNT_INT64;
362                }
363            }
364            break;
365        case Datatype.CLASS_FLOAT:
366            if (tsize == Datatype.NATIVE) {
367                tid = HDFConstants.DFNT_FLOAT;
368            }
369            else if (tsize == 4) {
370                tid = HDFConstants.DFNT_FLOAT32;
371            }
372            else if (tsize == 8) {
373                tid = HDFConstants.DFNT_FLOAT64;
374            }
375            break;
376        case Datatype.CLASS_CHAR:
377            if (isUnsigned()) {
378                tid = HDFConstants.DFNT_UCHAR;
379            }
380            else {
381                tid = HDFConstants.DFNT_CHAR;
382            }
383            break;
384        case Datatype.CLASS_STRING:
385            tid = HDFConstants.DFNT_CHAR;
386            break;
387        default:
388            log.debug("createNative(): unknown datatype class {}", tclass);
389        }
390
391        return tid;
392    }
393
394    /*
395     * (non-Javadoc)
396     *
397     * @see hdf.object.Datatype#close(int)
398     */
399    @Override
400    public void close(long id)
401    {
402        // No implementation
403    }
404
405    // Implementing MetaDataContainer
406    /**
407     * Retrieves the object's metadata, such as attributes, from the file.
408     *
409     * Metadata, such as attributes, is stored in a List.
410     *
411     * @param attrPropList
412     *             the list of properties to get
413     *
414     * @return the list of metadata objects.
415     *
416     * @throws Exception
417     *             if the metadata can not be retrieved
418     */
419    @SuppressWarnings("rawtypes")
420    public List getMetadata(int... attrPropList) throws Exception
421    {
422        throw new UnsupportedOperationException("getMetadata(int... attrPropList) is not supported");
423    }
424
425    /**
426     * Check if the object has any attributes attached.
427     *
428     * @return true if it has any attributes, false otherwise.
429     */
430    @Override
431    public boolean hasAttribute()
432    {
433        return false;
434    }
435}