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}