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 final static 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(CLASS_INTEGER, NATIVE, NATIVE, SIGN_NONE);
044     * <li>to create 16-bit signed integer with big endian<br>
045     * H4Datatype type = new H4Dataype(CLASS_INTEGER, 2, ORDER_BE, NATIVE);
046     * <li>to create native float<br>
047     * H4Datatype type = new H4Dataype(CLASS_FLOAT, NATIVE, NATIVE, -1);
048     * <li>to create 64-bit double<br>
049     * H4Datatype type = new H4Dataype(CLASS_FLOAT, 8, NATIVE, -1);
050     * </ol>
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     * @param torder
056     *            the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX and ORDER_NONE
057     * @param tsign
058     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and MSGN
059     */
060    public H4Datatype(int tclass, int tsize, int torder, int tsign) {
061        super(tclass, tsize, torder, tsign);
062        datatypeDescription = getDescription();
063    }
064
065    /**
066     * Constructs a H4Datatype with a given native datatype identifier.
067     * <p>
068     * For example,
069     *
070     * <pre>
071     * Datatype dtype = new H4Datatype(HDFConstants.DFNT_INT32);
072     * </pre>
073     *
074     * will construct a datatype equivalent to
075     *
076     * <pre>
077     * new H4Datatype(CLASS_INTEGER, 4, NATIVE, SIGN_NONE);
078     * </pre>
079     *
080     * @see #fromNative(long nativeID)
081     *
082     * @param nativeID
083     *            the native datatype identifier.
084     */
085    public H4Datatype(long nativeID) {
086        super(nativeID);
087
088        fromNative(nativeID);
089        datatypeDescription = getDescription();
090    }
091
092    /*
093     * (non-Javadoc)
094     *
095     * @see hdf.object.DataFormat#hasAttribute()
096     */
097    @Override
098    public boolean hasAttribute() {
099        return false;
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        log.trace("fromNative(): start");
111
112        datatypeOrder = NATIVE;
113        datatypeSign = NATIVE;
114
115        switch ((int) tid) {
116            case HDFConstants.DFNT_CHAR:
117                datatypeClass = CLASS_CHAR;
118                datatypeSize = 1;
119                break;
120            case HDFConstants.DFNT_UCHAR8:
121                datatypeClass = CLASS_CHAR;
122                datatypeSize = 1;
123                datatypeSign = SIGN_NONE;
124                break;
125            case HDFConstants.DFNT_INT8:
126                datatypeClass = CLASS_INTEGER;
127                datatypeSize = 1;
128                break;
129            case HDFConstants.DFNT_UINT8:
130                datatypeClass = CLASS_INTEGER;
131                datatypeSize = 1;
132                datatypeSign = SIGN_NONE;
133                break;
134            case HDFConstants.DFNT_INT16:
135                datatypeClass = CLASS_INTEGER;
136                datatypeSize = 2;
137                break;
138            case HDFConstants.DFNT_UINT16:
139                datatypeClass = CLASS_INTEGER;
140                datatypeSize = 2;
141                datatypeSign = SIGN_NONE;
142                break;
143            case HDFConstants.DFNT_INT32:
144                datatypeClass = CLASS_INTEGER;
145                datatypeSize = 4;
146                break;
147            case HDFConstants.DFNT_UINT32:
148                datatypeClass = CLASS_INTEGER;
149                datatypeSize = 4;
150                datatypeSign = SIGN_NONE;
151                break;
152            case HDFConstants.DFNT_INT64:
153                datatypeClass = CLASS_INTEGER;
154                datatypeSize = 8;
155                break;
156            case HDFConstants.DFNT_UINT64:
157                datatypeClass = CLASS_INTEGER;
158                datatypeSize = 8;
159                datatypeSign = SIGN_NONE;
160                break;
161            case HDFConstants.DFNT_FLOAT32:
162                datatypeClass = CLASS_FLOAT;
163                datatypeSize = 4;
164                break;
165            case HDFConstants.DFNT_FLOAT64:
166                datatypeClass = CLASS_FLOAT;
167                datatypeSize = 8;
168                break;
169            default:
170                datatypeClass = CLASS_NO_CLASS;
171                break;
172        }
173
174        log.trace("Datatype class={} size={}", datatypeClass, datatypeSize);
175        log.trace("fromNative(): finish");
176    }
177
178    /**
179     * Allocate a 1D array large enough to hold a multidimensional array of 'datasize' elements of
180     * 'datatype' numbers.
181     *
182     * @param datatype
183     *            the data type
184     * @param datasize
185     *            the size of the data array
186     *
187     * @return an array of 'datasize' numbers of datatype.
188     *
189     * @throws OutOfMemoryError
190     *             if the array cannot be allocated
191     */
192    public static final Object allocateArray(long datatype, int datasize) throws OutOfMemoryError {
193        log.trace("allocateArray(): start");
194
195        if (datasize <= 0) {
196            log.debug("datasize <= 0");
197            log.trace("allocateArray(): finish");
198            return null;
199        }
200
201        Object data = null;
202
203        switch ((int) datatype) {
204            case HDFConstants.DFNT_CHAR:
205            case HDFConstants.DFNT_UCHAR8:
206            case HDFConstants.DFNT_UINT8:
207            case HDFConstants.DFNT_INT8:
208                log.trace("allocateArray(): allocating byte array of size {}", datasize);
209                data = new byte[datasize];
210                break;
211            case HDFConstants.DFNT_INT16:
212            case HDFConstants.DFNT_UINT16:
213                log.trace("allocateArray(): allocating short array of size {}", datasize);
214                data = new short[datasize];
215                break;
216            case HDFConstants.DFNT_INT32:
217            case HDFConstants.DFNT_UINT32:
218                log.trace("allocateArray(): allocating int array of size {}", datasize);
219                data = new int[datasize];
220                break;
221            case HDFConstants.DFNT_INT64:
222            case HDFConstants.DFNT_UINT64:
223                log.trace("allocateArray(): allocating long array of size {}", datasize);
224                data = new long[datasize];
225                break;
226            case HDFConstants.DFNT_FLOAT32:
227                log.trace("allocateArray(): allocating float array of size {}", datasize);
228                data = new float[datasize];
229                break;
230            case HDFConstants.DFNT_FLOAT64:
231                log.trace("allocateArray(): allocating double array of size {}", datasize);
232                data = new double[datasize];
233                break;
234            default:
235                log.debug("allocateArray(): unknown datatype {}", datatype);
236                data = null;
237                break;
238        }
239
240        log.trace("allocateArray(): finish");
241        return data;
242    }
243
244    /*
245     * (non-Javadoc)
246     *
247     * @see hdf.object.Datatype#getDatatypeDescription()
248     */
249    @Override
250    public String getDescription() {
251        log.trace("getDescription(): start");
252
253        if (datatypeDescription != null) {
254            log.trace("getDescription(): finish");
255            return datatypeDescription;
256        }
257
258        String description = null;
259
260        switch (datatypeClass) {
261            case CLASS_CHAR:
262                description = "8-bit " + (isUnsigned() ? "unsigned " : "") + "character";
263                break;
264            case CLASS_INTEGER:
265                description = String.valueOf(datatypeSize * 8) + "-bit " + (isUnsigned() ? "unsigned " : "") + "integer";
266                break;
267            case CLASS_FLOAT:
268                description = String.valueOf(datatypeSize * 8) + "-bit floating-point";
269                break;
270            default:
271                description = "Unknown";
272                break;
273        }
274
275        log.trace("getDescription(): finish");
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        log.trace("isUnsigned(): start");
299
300        boolean unsigned = false;
301
302        switch((int) datatype) {
303            case HDFConstants.DFNT_UCHAR8:
304            case HDFConstants.DFNT_UINT8:
305            case HDFConstants.DFNT_UINT16:
306            case HDFConstants.DFNT_UINT32:
307            case HDFConstants.DFNT_UINT64:
308                unsigned = true;
309                break;
310            default:
311                log.debug("isUnsigned(): unknown datatype {}", datatype);
312                unsigned = false;
313                break;
314        }
315
316        log.trace("isUnsigned(): finish");
317        return unsigned;
318    }
319
320    @Override
321    public boolean isText() {
322        return (Datatype.CLASS_STRING == getDatatypeClass());
323    }
324
325    /*
326     * (non-Javadoc)
327     * @see hdf.object.Datatype#createNative()
328     */
329    @Override
330    public long createNative()
331    {
332        log.trace("createNative(): start");
333
334        long tid = -1;
335        int tclass = getDatatypeClass();
336        int tsize = (int) getDatatypeSize();
337
338        // figure the datatype
339        switch (tclass) {
340            case Datatype.CLASS_INTEGER:
341                if (tsize == 1) {
342                    if (isUnsigned()) {
343                        tid = HDFConstants.DFNT_UINT8;
344                    }
345                    else {
346                        tid = HDFConstants.DFNT_INT8;
347                    }
348                }
349                else if (tsize == 2) {
350                    if (isUnsigned()) {
351                        tid = HDFConstants.DFNT_UINT16;
352                    }
353                    else {
354                        tid = HDFConstants.DFNT_INT16;
355                    }
356                }
357                else if ((tsize == 4) || (tsize == NATIVE)) {
358                    if (isUnsigned()) {
359                        tid = HDFConstants.DFNT_UINT32;
360                    }
361                    else {
362                        tid = HDFConstants.DFNT_INT32;
363                    }
364                }
365                else if (tsize == 8) {
366                    if (isUnsigned()) {
367                        tid = HDFConstants.DFNT_UINT64;
368                    }
369                    else {
370                        tid = HDFConstants.DFNT_INT64;
371                    }
372                }
373                break;
374            case Datatype.CLASS_FLOAT:
375                if (tsize == Datatype.NATIVE) {
376                    tid = HDFConstants.DFNT_FLOAT;
377                }
378                else if (tsize == 4) {
379                    tid = HDFConstants.DFNT_FLOAT32;
380                }
381                else if (tsize == 8) {
382                    tid = HDFConstants.DFNT_FLOAT64;
383                }
384                break;
385            case Datatype.CLASS_CHAR:
386                if (isUnsigned()) {
387                    tid = HDFConstants.DFNT_UCHAR;
388                }
389                else {
390                    tid = HDFConstants.DFNT_CHAR;
391                }
392                break;
393            case Datatype.CLASS_STRING:
394                tid = HDFConstants.DFNT_CHAR;
395                break;
396            default:
397                log.debug("createNative(): unknown datatype class {}", tclass);
398        }
399
400        log.trace("createNative(): finish");
401        return tid;
402    }
403
404    /*
405     * (non-Javadoc)
406     *
407     * @see hdf.object.Datatype#close(int)
408     */
409    @Override
410    public void close(long id) {
411        ;
412    }
413
414    // Implementing DataFormat
415    @SuppressWarnings("rawtypes")
416    public List getMetadata(int... attrPropList) throws Exception {
417        throw new UnsupportedOperationException("getMetadata(int... attrPropList) is not supported");
418    }
419}