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