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.h5; 016 017import java.lang.reflect.Array; 018import java.math.BigDecimal; 019import java.math.BigInteger; 020import java.math.MathContext; 021import java.util.ArrayList; 022import java.util.Arrays; 023import java.util.BitSet; 024import java.util.HashMap; 025import java.util.Iterator; 026import java.util.List; 027import java.util.Map.Entry; 028import java.util.Objects; 029import java.util.Vector; 030 031import hdf.hdf5lib.H5; 032import hdf.hdf5lib.HDF5Constants; 033import hdf.hdf5lib.HDFNativeData; 034import hdf.hdf5lib.exceptions.HDF5Exception; 035import hdf.hdf5lib.exceptions.HDF5LibraryException; 036import hdf.hdf5lib.structs.H5O_info_t; 037 038import hdf.object.Attribute; 039import hdf.object.CompoundDS; 040import hdf.object.Datatype; 041import hdf.object.FileFormat; 042 043import hdf.object.h5.H5MetaDataContainer; 044 045/** 046 * This class defines HDF5 datatype characteristics and APIs for a data type. 047 * 048 * This class provides several methods to convert an HDF5 datatype identifier to a datatype object, and vice versa. A 049 * datatype object is described by four basic fields: datatype class, size, byte order, and sign, while an HDF5 datatype 050 * is presented by a datatype identifier. 051 * 052 * @version 1.1 9/4/2007 053 * @author Peter X. Cao 054 */ 055public class H5Datatype extends Datatype 056{ 057 private static final long serialVersionUID = -750546422258749792L; 058 059 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(H5Datatype.class); 060 061 /** 062 * The metadata object for this data object. Members of the metadata are instances of Attribute. 063 */ 064 private H5MetaDataContainer objMetadata; 065 066 /** the datatype is an object reference */ 067 private boolean isRefObj = false; 068 069 /** the datatype is a region reference */ 070 private boolean isRegRef = false; 071 072 /** the object properties */ 073 private H5O_info_t objInfo; 074 075 /** 076 * The native class of the datatype. 077 */ 078 private int nativeClass = -1; 079 080 /** The native Precision properties of the number datatype. */ 081 private long nativePrecision = 0; 082 /** The native Offset properties of the number datatype. */ 083 private int nativeOffset = -1; 084 /** The native PadLSB properties of the number datatype. */ 085 private int nativePadLSB = -1; 086 /** The native PadMSB properties of the number datatype. */ 087 private int nativePadMSB = -1; 088 089 /** The native ebias properties of the float datatype. */ 090 private long nativeFPebias = 0; 091 /** The native spos properties of the float datatype. */ 092 private long nativeFPspos = -1; 093 /** The native epos properties of the float datatype. */ 094 private long nativeFPepos = -1; 095 /** The native esize properties of the float datatype. */ 096 private long nativeFPesize = -1; 097 /** The native mpos properties of the float datatype. */ 098 private long nativeFPmpos = -1; 099 /** The native msize properties of the float datatype. */ 100 private long nativeFPmsize = -1; 101 /** The native norm properties of the float datatype. */ 102 private int nativeFPnorm = -1; 103 /** The native inpad properties of the float datatype. */ 104 private int nativeFPinpad = -1; 105 106 /** The native padding properties of the string datatype. */ 107 private int nativeStrPad = -1; 108 /** The native CSET properties of the string datatype. */ 109 private int nativeStrCSET = -1; 110 111 /** 112 * The tag for an opaque datatype. 113 */ 114 private String opaqueTag = null; 115 116 /** 117 * Constructs an named HDF5 data type object for a given file, dataset name and group path. 118 * 119 * The datatype object represents an existing named datatype in file. For example, 120 * 121 * <pre> 122 * new H5Datatype(file, "dtype1", "/g0") 123 * </pre> 124 * 125 * constructs a datatype object that corresponds to the dataset,"dset1", at group "/g0". 126 * 127 * @param theFile 128 * the file that contains the datatype. 129 * @param theName 130 * the name of the dataset such as "dset1". 131 * @param thePath 132 * the group path to the dataset such as "/g0/". 133 */ 134 public H5Datatype(FileFormat theFile, String theName, String thePath) { 135 this(theFile, theName, thePath, null); 136 } 137 138 /** 139 * @deprecated Not for public use in the future. <br> 140 * Using {@link #H5Datatype(FileFormat, String, String)} 141 * 142 * @param theFile 143 * the file that contains the datatype. 144 * @param theName 145 * the name of the dataset such as "dset1". 146 * @param thePath 147 * the group path to the dataset such as "/g0/". 148 * @param oid 149 * the oid of the dataset. 150 */ 151 @Deprecated 152 public H5Datatype(FileFormat theFile, String theName, String thePath, long[] oid) { 153 super(theFile, theName, thePath, oid); 154 objInfo = new H5O_info_t(-1L, -1L, 0, 0, -1L, 0L, 0L, 0L, 0L, null, null, null); 155 objMetadata = new H5MetaDataContainer(theFile, theName, thePath, this); 156 157 if (theFile != null) { 158 if (oid == null) { 159 // retrieve the object ID 160 try { 161 byte[] refBuf = H5.H5Rcreate(theFile.getFID(), this.getFullName(), HDF5Constants.H5R_OBJECT, -1); 162 this.oid = new long[1]; 163 this.oid[0] = HDFNativeData.byteToLong(refBuf, 0); 164 } 165 catch (Exception ex) { 166 log.debug("constructor ID {} for {} failed H5Rcreate", theFile.getFID(), this.getFullName()); 167 } 168 } 169 170 long tid = HDF5Constants.H5I_INVALID_HID; 171 try { 172 tid = open(); 173 } 174 catch (Exception ex) { 175 log.debug("constructor H5Topen() failure"); 176 } 177 finally { 178 close(tid); 179 } 180 } 181 else 182 this.oid = null; 183 } 184 185 /** 186 * Constructs a Datatype with specified class, size, byte order and sign. 187 * 188 * The following is a list of a few examples of H5Datatype. 189 * <ol> 190 * <li>to create unsigned native integer<br> 191 * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE); 192 * <li>to create 16-bit signed integer with big endian<br> 193 * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, 2, Datatype.ORDER_BE, Datatype.NATIVE); 194 * <li>to create native float<br> 195 * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE); 196 * <li>to create 64-bit double<br> 197 * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE); 198 * </ol> 199 * 200 * @param tclass 201 * the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc. 202 * @param tsize 203 * the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4. 204 * Valid values are NATIVE or a positive value. For string datatypes, -1 is also 205 * a valid value (to create a variable-length string). 206 * @param torder 207 * the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX, 208 * ORDER_NONE and NATIVE. 209 * @param tsign 210 * the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE. 211 * 212 * @throws Exception 213 * if there is an error 214 */ 215 public H5Datatype(int tclass, int tsize, int torder, int tsign) throws Exception { 216 this(tclass, tsize, torder, tsign, null); 217 } 218 219 /** 220 * Constructs a Datatype with specified class, size, byte order and sign. 221 * 222 * The following is a list of a few examples of H5Datatype. 223 * <ol> 224 * <li>to create unsigned native integer<br> 225 * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE); 226 * <li>to create 16-bit signed integer with big endian<br> 227 * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, 2, Datatype.ORDER_BE, Datatype.NATIVE); 228 * <li>to create native float<br> 229 * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE); 230 * <li>to create 64-bit double<br> 231 * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE); 232 * </ol> 233 * 234 * @param tclass 235 * the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc. 236 * @param tsize 237 * the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4. 238 * Valid values are NATIVE or a positive value. For string datatypes, -1 is also 239 * a valid value (to create a variable-length string). 240 * @param torder 241 * the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX, 242 * ORDER_NONE and NATIVE. 243 * @param tsign 244 * the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE. 245 * @param tbase 246 * the base datatype of the new datatype 247 * 248 * @throws Exception 249 * if there is an error 250 */ 251 public H5Datatype(int tclass, int tsize, int torder, int tsign, Datatype tbase) throws Exception { 252 this(tclass, tsize, torder, tsign, tbase, null); 253 } 254 255 /** 256 * Constructs a Datatype with specified class, size, byte order and sign. 257 * 258 * The following is a list of a few examples of H5Datatype. 259 * <ol> 260 * <li>to create unsigned native integer<br> 261 * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE); 262 * <li>to create 16-bit signed integer with big endian<br> 263 * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, 2, Datatype.ORDER_BE, Datatype.NATIVE); 264 * <li>to create native float<br> 265 * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE); 266 * <li>to create 64-bit double<br> 267 * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE); 268 * </ol> 269 * 270 * @param tclass 271 * the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc. 272 * @param tsize 273 * the size of the datatype in bytes, e.g. for a 32-bit integer, the 274 * size is 4. Valid values are NATIVE or a positive value. For string 275 * datatypes, -1 is also a valid value (to create a variable-length 276 * string). 277 * @param torder 278 * the byte order of the datatype. Valid values are ORDER_LE, 279 * ORDER_BE, ORDER_VAX, ORDER_NONE and NATIVE. 280 * @param tsign 281 * the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and 282 * NATIVE. 283 * @param tbase 284 * the base datatype of the new datatype 285 * @param pbase 286 * the parent datatype of the new datatype 287 * 288 * @throws Exception 289 * if there is an error 290 */ 291 public H5Datatype(int tclass, int tsize, int torder, int tsign, Datatype tbase, Datatype pbase) throws Exception { 292 super(tclass, tsize, torder, tsign, tbase, pbase); 293 datatypeDescription = getDescription(); 294 } 295 296 /** 297 * Constructs a Datatype with a given native datatype identifier. 298 * 299 * For example, if the datatype identifier is a 32-bit unsigned integer created from HDF5, 300 * 301 * <pre> 302 * int tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32); 303 * Datatype dtype = new Datatype(tid); 304 * </pre> 305 * 306 * will construct a datatype equivalent to new Datatype(Datatype.CLASS_INTEGER, 4, Datatype.NATIVE, Datatype.SIGN_NONE); 307 * 308 * @see #fromNative(long nativeID) 309 * 310 * @param theFile 311 * the file that contains the datatype. 312 * @param nativeID 313 * the native datatype identifier. 314 * 315 * @throws Exception 316 * if there is an error 317 */ 318 public H5Datatype(FileFormat theFile, long nativeID) throws Exception { 319 this(theFile, nativeID, null); 320 } 321 322 /** 323 * Constructs a Datatype with a given native datatype identifier. 324 * 325 * For example, if the datatype identifier is a 32-bit unsigned integer created from HDF5, 326 * 327 * <pre> 328 * int tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32); 329 * Datatype dtype = new Datatype(tid); 330 * </pre> 331 * 332 * will construct a datatype equivalent to new Datatype(Datatype.CLASS_INTEGER, 4, Datatype.NATIVE, Datatype.SIGN_NONE); 333 * 334 * @see #fromNative(long nativeID) 335 * 336 * @param theFile 337 * the file that contains the datatype. 338 * @param nativeID 339 * the native datatype identifier. 340 * @param pbase 341 * the parent datatype of the new datatype 342 * 343 * @throws Exception 344 * if there is an error 345 */ 346 public H5Datatype(FileFormat theFile, long nativeID, Datatype pbase) throws Exception { 347 super(theFile, nativeID, pbase); 348 fromNative(nativeID); 349 datatypeDescription = getDescription(); 350 } 351 352 /** 353 * Opens access to a named datatype. 354 * 355 * It calls H5.H5Topen(loc, name). 356 * 357 * @return the datatype identifier if successful; otherwise returns negative value. 358 * 359 * @see hdf.hdf5lib.H5#H5Topen(long, String, long) 360 */ 361 @Override 362 public long open() { 363 long tid = HDF5Constants.H5I_INVALID_HID; 364 365 if (fileFormat != null) { 366 try { 367 tid = H5.H5Topen(getFID(), getFullName(), HDF5Constants.H5P_DEFAULT); 368 fromNative(tid); 369 log.trace("open(): tid={}", tid); 370 } 371 catch (HDF5Exception ex) { 372 log.debug("open(): Failed to open datatype {}", getFullName(), ex); 373 tid = HDF5Constants.H5I_INVALID_HID; 374 } 375 } 376 377 return tid; 378 } 379 380 /** 381 * Closes a datatype identifier. 382 * 383 * It calls H5.H5close(tid). 384 * 385 * @param tid 386 * the datatype ID to close 387 */ 388 @Override 389 public void close(long tid) { 390 if (tid >= 0) { 391 try { 392 H5.H5Tclose(tid); 393 } 394 catch (HDF5Exception ex) { 395 log.debug("close(): H5Tclose(tid {}) failure: ", tid, ex); 396 } 397 } 398 } 399 400 /** 401 * Check if the object has any attributes attached. 402 * 403 * @return true if it has any attributes, false otherwise. 404 */ 405 @Override 406 public boolean hasAttribute() { 407 objInfo.num_attrs = objMetadata.getObjectAttributeSize(); 408 409 if (objInfo.num_attrs < 0) { 410 long tid = open(); 411 if (tid > 0) { 412 try { 413 objInfo = H5.H5Oget_info(tid); 414 } 415 catch (Exception ex) { 416 objInfo.num_attrs = 0; 417 log.debug("hasAttribute(): get object info failure: ", ex); 418 } 419 finally { 420 close(tid); 421 } 422 objMetadata.setObjectAttributeSize((int) objInfo.num_attrs); 423 } 424 else { 425 log.debug("hasAttribute(): could not open group"); 426 } 427 } 428 429 log.trace("hasAttribute(): nAttributes={}", objInfo.num_attrs); 430 return (objInfo.num_attrs > 0); 431 } 432 433 /** 434 * Converts values in an Enumeration Datatype to names. 435 * 436 * This method searches the identified enumeration datatype for the values appearing in 437 * <code>inValues</code> and returns the names corresponding to those values. If a given value is 438 * not found in the enumeration datatype, the name corresponding to that value will be set to 439 * <code>"ENUM ERR value"</code> in the string array that is returned. 440 * 441 * If the method fails in general, null will be returned instead of a String array. An empty 442 * <code>inValues</code> parameter would cause general failure. 443 * 444 * @param inValues 445 * The array of enumerations values to be converted. 446 * 447 * @return The string array of names if successful; otherwise return null. 448 * 449 * @throws HDF5Exception 450 * If there is an error at the HDF5 library level. 451 * 452 */ 453 public String[] convertEnumValueToName(Object inValues) throws HDF5Exception { 454 log.trace("convertEnumValueToName() inValues={} start", inValues); 455 456 if (inValues == null) { 457 log.debug("convertEnumValueToName() failure: in values null "); 458 return null; 459 } 460 461 int inSize = 0; 462 String[] outNames = null; 463 String cName = inValues.getClass().getName(); 464 boolean isArray = cName.lastIndexOf('[') >= 0; 465 if (isArray) 466 inSize = Array.getLength(inValues); 467 else 468 inSize = 1; 469 470 if (inSize <= 0) { 471 log.debug("convertEnumValueToName() failure: inSize length invalid"); 472 log.debug("convertEnumValueToName(): inValues={} inSize={}", inValues, inSize); 473 return null; 474 } 475 476 if (enumMembers == null || enumMembers.size() <= 0) { 477 log.debug("convertEnumValueToName(): no members"); 478 return null; 479 } 480 481 log.trace("convertEnumValueToName(): inSize={} nMembers={} enums={}", inSize, enumMembers.size(), enumMembers); 482 outNames = new String[inSize]; 483 for (int i = 0; i < inSize; i++) { 484 if (isArray) { 485 if (enumMembers.containsKey(String.valueOf(Array.get(inValues, i)))) 486 outNames[i] = enumMembers.get(String.valueOf(Array.get(inValues, i))); 487 else 488 outNames[i] = "**ENUM ERR " + Array.get(inValues, i) + "**"; 489 } 490 else { 491 if (enumMembers.containsKey(String.valueOf(inValues))) 492 outNames[i] = enumMembers.get(String.valueOf(inValues)); 493 else 494 outNames[i] = "**ENUM ERR " + inValues + "**"; 495 } 496 } 497 498 return outNames; 499 } 500 501 /** 502 * Converts names in an Enumeration Datatype to values. 503 * 504 * This method searches the identified enumeration datatype for the names appearing in 505 * <code>inValues</code> and returns the values corresponding to those names. 506 * 507 * @param in 508 * The array of enumerations names to be converted. 509 * 510 * @return The int array of values if successful; otherwise return null. 511 * 512 * @throws HDF5Exception 513 * If there is an error at the HDF5 library level. 514 * 515 */ 516 public Object[] convertEnumNameToValue(String[] in) throws HDF5Exception { 517 int size = 0; 518 519 if (in == null) { 520 log.debug("convertEnumNameToValue() failure: in values null"); 521 return null; 522 } 523 524 if ((size = Array.getLength(in)) <= 0) { 525 log.debug("convertEnumNameToValue() failure: in size not valid"); 526 return null; 527 } 528 529 if (enumMembers == null || enumMembers.size() <= 0) { 530 log.debug("convertEnumNameToValue(): no members"); 531 return null; 532 } 533 534 Object[] out = null; 535 if (datatypeSize == 1) 536 out = new Byte[size]; 537 else if (datatypeSize == 2) 538 out = new Short[size]; 539 else if (datatypeSize == 4) 540 out = new Integer[size]; 541 else if (datatypeSize == 8) 542 out = new Long[size]; 543 else 544 out = new Object[size]; 545 546 for (int i = 0; i < size; i++) { 547 if (in[i] == null || in[i].length() <= 0) 548 continue; 549 550 for (Entry<String, String> entry : enumMembers.entrySet()) { 551 if (Objects.equals(in[i], entry.getValue())) { 552 if (datatypeSize == 1) { 553 log.trace("convertEnumNameToValue(): ENUM is H5T_NATIVE_INT8"); 554 out[i] = Byte.parseByte(entry.getKey()); 555 } 556 else if (datatypeSize == 2) { 557 log.trace("convertEnumNameToValue(): CLASS_INT-ENUM is H5T_NATIVE_INT16"); 558 out[i] = Short.parseShort(entry.getKey()); 559 } 560 else if (datatypeSize == 4) { 561 log.trace("convertEnumNameToValue(): CLASS_INT-ENUM is H5T_NATIVE_INT32"); 562 out[i] = Integer.parseInt(entry.getKey()); 563 } 564 else if (datatypeSize == 8) { 565 log.trace("convertEnumNameToValue(): CLASS_INT-ENUM is H5T_NATIVE_INT64"); 566 out[i] = Long.parseLong(entry.getKey()); 567 } 568 else { 569 log.debug("convertEnumNameToValue(): enum datatypeSize incorrect"); 570 out[i] = -1; 571 } 572 break; 573 } 574 } 575 } 576 577 return out; 578 } 579 580 /** 581 * Convert from an array of BigDecimal into an array of bytes 582 * 583 * @param start 584 * The position in the input array of BigDecimal to start 585 * @param len 586 * The number of 'BigDecimal' to convert 587 * @param data 588 * The input array of BigDecimal 589 * @return an array of bytes 590 */ 591 public byte[] bigDecimalToByte(int start, int len, BigDecimal[] data) { 592 int ii; 593 byte[] bd = new byte[(int)datatypeSize]; 594 byte[] bdconv = new byte[(int)datatypeSize]; 595 byte[] bdbytes = new byte[(int)datatypeSize * len]; 596 597 for (ii = 0; ii < len; ii++) { 598 BigDecimal entry = data[start + ii]; 599 bdconv = convertBigDecimalToByte(entry); 600 /* bitsets operate assuming LE order, BigInteger/BigDecimal expect BE */ 601 if (datatypeOrder == ORDER_BE) { 602 int k = 0; 603 for(int j = (int)datatypeSize - 1; j >= 0; j--) 604 bd[k++] = bdconv[j]; 605 } 606 else 607 System.arraycopy(bdconv, 0, bd, 0, (int)datatypeSize); 608 System.arraycopy(bd, 0, bdbytes, ii * 16, 16); 609 } 610 return bdbytes; 611 } 612 613 /** 614 * Convert from a single BigDecimal object from an array of BigDecimal into an array of bytes 615 * 616 * @param start 617 * The position in the input array of BigDecimal to start 618 * @param data 619 * The input Float 620 * @return an array of bytes 621 */ 622 public byte[] bigDecimalToByte(BigDecimal[] data, int start) { 623 byte[] bdbytes = new byte[(int)datatypeSize]; 624 bdbytes = bigDecimalToByte(start, 1, data); 625 return bdbytes; 626 } 627 628 /** 629 * Convert a BigDecimal to a byte array . 630 * 631 * @param num 632 * The BigDecimal number to convert 633 * 634 * @return A byte array representing the BigDecimal. 635 */ 636 public byte[] convertBigDecimalToByte(BigDecimal num) { 637 BigInteger sig = new BigInteger(num.unscaledValue().toString()); 638 byte[] bsig = sig.toByteArray(); 639 int scale = num.scale(); 640 byte[] bscale = new byte[] { 641 (byte)(scale >>> 24), 642 (byte)(scale >>> 16), 643 (byte)(scale >>> 8), 644 (byte)(scale) 645 }; 646 byte[] both = new byte[bscale.length + bsig.length]; 647 System.arraycopy(bscale, 0, both, 0, bscale.length); 648 System.arraycopy(bsig, 0, both, bscale.length, bsig.length); 649 return both; 650 } 651 652 /** 653 * Convert a range from an array of bytes into an array of BigDecimal 654 * 655 * @param start 656 * The position in the input array of bytes to start 657 * @param len 658 * The number of 'BigDecimal' to convert 659 * @param data 660 * The input array of bytes 661 * @return an array of 'len' BigDecimal 662 */ 663 public BigDecimal[] byteToBigDecimal(int start, int len, byte[] data) { 664 int ii; 665 byte[] bd = new byte[(int)datatypeSize]; 666 BigDecimal[] BDarray = new BigDecimal[len]; 667 668 for (ii = 0; ii < len; ii++) { 669 int rawpos = (start + ii) * (int)datatypeSize; 670 /* bitsets operate assuming LE order, BigInteger/BigDecimal expect BE */ 671 if (datatypeOrder == ORDER_BE) { 672 int k = 0; 673 for(int j = (int)datatypeSize - 1; j >= 0; j--) 674 bd[k++] = data[rawpos + j]; 675 } 676 else 677 System.arraycopy(data, rawpos, bd, 0, (int)datatypeSize); 678 BDarray[ii] = convertByteToBigDecimal(bd); 679 } 680 return BDarray; 681 } 682 683 /** 684 * Convert 4 bytes from an array of bytes into a single BigDecimal 685 * 686 * @param start 687 * The position in the input array of bytes to start 688 * @param data 689 * The input array of bytes 690 * @return The BigDecimal value of the bytes. 691 */ 692 public BigDecimal byteToBigDecimal(byte[] data, int start) { 693 BigDecimal[] bdval = new BigDecimal[1]; 694 bdval = byteToBigDecimal(start, 1, data); 695 return (bdval[0]); 696 } 697 698 /** 699 * Convert byte array data to a BigDecimal. 700 * 701 * @param raw 702 * The byte array to convert to a BigDecimal 703 * 704 * @return A BigDecimal representing the byte array. 705 */ 706 public BigDecimal convertByteToBigDecimal(byte[] raw) { 707 BitSet rawset = BitSet.valueOf(raw); 708 709 boolean sign = rawset.get(nativeOffset + (int)nativeFPspos); 710 BitSet mantissaset = rawset.get(nativeOffset + (int)nativeFPmpos, nativeOffset + (int)nativeFPmpos + (int)nativeFPmsize); 711 BitSet exponentset = rawset.get(nativeOffset + (int)nativeFPepos, nativeOffset + (int)nativeFPepos + (int)nativeFPesize); 712 byte[] expraw = Arrays.copyOf(exponentset.toByteArray(), (int)(nativeFPesize + 7)/8); 713 byte[] bexp = new byte[expraw.length]; 714 /* bitsets operate assuming LE order, BigInteger/BigDecimal expect BE */ 715 if (datatypeOrder == ORDER_LE) { 716 int k = 0; 717 for(int j = expraw.length - 1; j >= 0; j--) 718 bexp[k++] = expraw[j]; 719 } 720 else 721 System.arraycopy(expraw, 0, bexp, 0, expraw.length); 722 BigInteger bscale = new BigInteger(bexp); 723 long scale = bscale.longValue(); 724 scale -= nativeFPebias; 725 double powscale = Math.pow(2, scale); 726 727 byte[] manraw = Arrays.copyOf(mantissaset.toByteArray(), (int)(nativeFPmsize + 7)/8); 728 byte[] bman = new byte[manraw.length]; 729 /* bitsets operate assuming LE order, BigInteger/BigDecimal expect BE */ 730 if (datatypeOrder == ORDER_BE) { 731 int k = 0; 732 for(int j = manraw.length - 1; j >= 0; j--) 733 bman[k++] = manraw[j]; 734 } 735 else 736 System.arraycopy(manraw, 0, bman, 0, manraw.length); 737 BitSet manset = BitSet.valueOf(bman); 738 739 // calculate mantissa value 740 double val = 0.0; 741 for (int i = 0; i < (int)nativeFPmsize; i++) { 742 if (manset.get((int)nativeFPmsize - 1 - i)) 743 val += Math.pow(2, -(i)); 744 } 745 if (nativeFPnorm == HDF5Constants.H5T_NORM_IMPLIED || nativeFPnorm == HDF5Constants.H5T_NORM_MSBSET) 746 val += 1; 747 BigDecimal sig = BigDecimal.valueOf(val); 748 if (sign) 749 sig.negate(MathContext.DECIMAL128); 750 return sig.multiply(new BigDecimal(powscale, MathContext.DECIMAL128)); 751 } 752 753 /* 754 * (non-Javadoc) 755 * 756 * @see hdf.object.Datatype#fromNative(int) 757 */ 758 @Override 759 public void fromNative(long tid) { 760 log.trace("fromNative(): start: tid={}", tid); 761 long tsize = -1; 762 int torder = -1; 763 boolean isChar = false; 764 boolean isUchar = false; 765 766 if (tid < 0) { 767 datatypeClass = CLASS_NO_CLASS; 768 } 769 else { 770 try { 771 nativeClass = H5.H5Tget_class(tid); 772 tsize = H5.H5Tget_size(tid); 773 isVariableStr = H5.H5Tis_variable_str(tid); 774 isVLEN = false; 775 log.trace("fromNative(): tclass={}, tsize={}, torder={}, isVLEN={}", nativeClass, tsize, torder, isVLEN); 776 if (H5.H5Tcommitted(tid)) { 777 isNamed = true; 778 try { 779 setFullname(null, H5.H5Iget_name(tid)); 780 } 781 catch (Exception nex) { 782 log.debug("fromNative(): setName failure: {}", nex.getMessage()); 783 } 784 log.trace("fromNative(): path={} name={}", this.getPath(), this.getName()); 785 } 786 log.trace("fromNative(): isNamed={}", isNamed()); 787 } 788 catch (Exception ex) { 789 log.debug("fromNative(): failure: ", ex); 790 datatypeClass = CLASS_NO_CLASS; 791 } 792 793 try { 794 isUchar = H5.H5Tequal(tid, HDF5Constants.H5T_NATIVE_UCHAR); 795 isChar = (H5.H5Tequal(tid, HDF5Constants.H5T_NATIVE_CHAR) || isUchar); 796 log.trace("fromNative(): tclass={}, tsize={}, torder={}, isUchar={}, isChar={}", nativeClass, tsize, torder, isUchar, isChar); 797 } 798 catch (Exception ex) { 799 log.debug("fromNative(): native char type failure: ", ex); 800 } 801 802 datatypeOrder = HDF5Constants.H5T_ORDER_NONE; 803 boolean IsAtomic = datatypeClassIsAtomic(nativeClass); 804 if (IsAtomic || (nativeClass == HDF5Constants.H5T_COMPOUND)) { 805 try { 806 torder = H5.H5Tget_order(tid); 807 datatypeOrder = (torder == HDF5Constants.H5T_ORDER_BE) ? ORDER_BE : ORDER_LE; 808 } 809 catch (Exception ex) { 810 log.debug("fromNative(): get_order failure: ", ex); 811 } 812 } 813 814 if (IsAtomic && !datatypeClassIsOpaque(nativeClass)) { 815 try { 816 nativePrecision = H5.H5Tget_precision_long(tid); 817 } 818 catch (Exception ex) { 819 log.debug("fromNative(): get_precision failure: ", ex); 820 } 821 822 try { 823 nativeOffset = H5.H5Tget_offset(tid); 824 } 825 catch (Exception ex) { 826 log.debug("fromNative(): get_offset failure: ", ex); 827 } 828 829 try { 830 int[] pads = new int[2]; 831 H5.H5Tget_pad(tid, pads); 832 nativePadLSB = pads[0]; 833 nativePadMSB = pads[1]; 834 } 835 catch (Exception ex) { 836 log.debug("fromNative(): get_pad failure: ", ex); 837 } 838 } 839 840 log.trace("fromNative(): isUchar={}, nativePrecision={}, nativeOffset={}, nativePadLSB={}, nativePadMSB={}", isUchar, nativePrecision, nativeOffset, nativePadLSB, 841 nativePadMSB); 842 843 datatypeSign = NATIVE; // default 844 if (nativeClass == HDF5Constants.H5T_ARRAY) { 845 long tmptid = HDF5Constants.H5I_INVALID_HID; 846 datatypeClass = CLASS_ARRAY; 847 try { 848 int ndims = H5.H5Tget_array_ndims(tid); 849 arrayDims = new long[ndims]; 850 H5.H5Tget_array_dims(tid, arrayDims); 851 852 tmptid = H5.H5Tget_super(tid); 853 baseType = new H5Datatype(this.fileFormat, tmptid, this); 854 if (baseType == null) { 855 log.debug("fromNative(): ARRAY datatype has null base type"); 856 throw new Exception("Datatype (ARRAY) has no base datatype"); 857 } 858 859 datatypeSign = baseType.getDatatypeSign(); 860 } 861 catch (Exception ex) { 862 log.debug("fromNative(): array type failure: ", ex); 863 } 864 finally { 865 close(tmptid); 866 } 867 } 868 else if (nativeClass == HDF5Constants.H5T_COMPOUND) { 869 datatypeClass = CLASS_COMPOUND; 870 871 try { 872 int nMembers = H5.H5Tget_nmembers(tid); 873 compoundMemberNames = new Vector<>(nMembers); 874 compoundMemberTypes = new Vector<>(nMembers); 875 compoundMemberOffsets = new Vector<>(nMembers); 876 log.trace("fromNative(): compound type nMembers={} start", nMembers); 877 878 for (int i = 0; i < nMembers; i++) { 879 String memberName = H5.H5Tget_member_name(tid, i); 880 log.trace("fromNative(): compound type [{}] name={} start", i, memberName); 881 long memberOffset = H5.H5Tget_member_offset(tid, i); 882 long memberID = HDF5Constants.H5I_INVALID_HID; 883 H5Datatype membertype = null; 884 try { 885 memberID = H5.H5Tget_member_type(tid, i); 886 membertype = new H5Datatype(this.fileFormat, memberID, this); 887 } 888 catch (Exception ex1) { 889 log.debug("fromNative(): compound type failure: ", ex1); 890 } 891 finally { 892 close(memberID); 893 } 894 895 compoundMemberNames.add(i, memberName); 896 compoundMemberOffsets.add(i, memberOffset); 897 compoundMemberTypes.add(i, membertype); 898 } 899 } 900 catch (HDF5LibraryException ex) { 901 log.debug("fromNative(): compound type failure: ", ex); 902 } 903 } 904 else if (nativeClass == HDF5Constants.H5T_INTEGER) { 905 datatypeClass = CLASS_INTEGER; 906 try { 907 log.trace("fromNative(): integer type"); 908 int tsign = H5.H5Tget_sign(tid); 909 datatypeSign = (tsign == HDF5Constants.H5T_SGN_NONE) ? SIGN_NONE : SIGN_2; 910 } 911 catch (Exception ex) { 912 log.debug("fromNative(): int type failure: ", ex); 913 } 914 } 915 else if (nativeClass == HDF5Constants.H5T_FLOAT) { 916 datatypeClass = CLASS_FLOAT; 917 try { 918 nativeFPebias = H5.H5Tget_ebias_long(tid); 919 } 920 catch (Exception ex) { 921 log.debug("fromNative(): get_ebias failure: ", ex); 922 } 923 try { 924 long[] fields = new long[5]; 925 H5.H5Tget_fields(tid, fields); 926 nativeFPspos = fields[0]; 927 nativeFPepos = fields[1]; 928 nativeFPesize = fields[2]; 929 nativeFPmpos = fields[3]; 930 nativeFPmsize = fields[4]; 931 } 932 catch (Exception ex) { 933 log.debug("fromNative(): get_fields failure: ", ex); 934 } 935 try { 936 nativeFPnorm = H5.H5Tget_norm(tid); 937 } 938 catch (Exception ex) { 939 log.debug("fromNative(): get_norm failure: ", ex); 940 } 941 try { 942 nativeFPinpad = H5.H5Tget_inpad(tid); 943 } 944 catch (Exception ex) { 945 log.debug("fromNative(): get_inpad failure: ", ex); 946 } 947 } 948 else if (isChar) { 949 datatypeClass = CLASS_CHAR; 950 datatypeSign = (isUchar) ? SIGN_NONE : SIGN_2; 951 log.trace("fromNative(): CLASS_CHAR:datatypeSign={}", datatypeSign); 952 } 953 else if (nativeClass == HDF5Constants.H5T_STRING) { 954 datatypeClass = CLASS_STRING; 955 try { 956 isVLEN = H5.H5Tdetect_class(tid, HDF5Constants.H5T_VLEN) || isVariableStr; 957 log.trace("fromNative(): H5T_STRING:var str type={}", isVLEN); 958 nativeStrPad = H5.H5Tget_strpad(tid); 959 } 960 catch (Exception ex) { 961 log.debug("fromNative(): var str type failure: ", ex); 962 } 963 try { 964 nativeStrCSET = H5.H5Tget_cset(tid); 965 } 966 catch (Exception ex) { 967 log.debug("fromNative(): H5T_STRING:get_cset failure: ", ex); 968 } 969 log.trace("fromNative(): H5T_STRING:nativeStrPad={}, nativeStrCSET={}", nativeStrPad, nativeStrCSET); 970 } 971 else if (nativeClass == HDF5Constants.H5T_REFERENCE) { 972 datatypeClass = CLASS_REFERENCE; 973 log.trace("fromNative(): reference type"); 974 try { 975 isRegRef = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_DSETREG); 976 } 977 catch (Exception ex) { 978 log.debug("fromNative(): H5T_STD_REF_DSETREG: ", ex); 979 } 980 try { 981 isRefObj = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_OBJ); 982 } 983 catch (Exception ex) { 984 log.debug("fromNative(): H5T_STD_REF_OBJ: ", ex); 985 } 986 } 987 else if (nativeClass == HDF5Constants.H5T_ENUM) { 988 datatypeClass = CLASS_ENUM; 989 long tmptid = HDF5Constants.H5I_INVALID_HID; 990 long basetid = HDF5Constants.H5I_INVALID_HID; 991 try { 992 log.trace("fromNative(): enum type"); 993 basetid = H5.H5Tget_super(tid); 994 tmptid = basetid; 995 basetid = H5.H5Tget_native_type(tmptid); 996 log.trace("fromNative(): enum type basetid={}", basetid); 997 if (basetid >= 0) { 998 baseType = new H5Datatype(this.fileFormat, tmptid, this); 999 datatypeSign = baseType.getDatatypeSign(); 1000 } 1001 } 1002 catch (Exception ex) { 1003 log.debug("fromNative(): enum type failure: ", ex); 1004 } 1005 finally { 1006 close(tmptid); 1007 close(basetid); 1008 } 1009 try { 1010 int enumMemberCount = H5.H5Tget_nmembers(tid); 1011 String name = null; 1012 String enumStr = null; 1013 byte[] val = new byte[(int)tsize]; 1014 enumMembers = new HashMap<>(); 1015 for (int i = 0; i < enumMemberCount; i++) { 1016 name = H5.H5Tget_member_name(tid, i); 1017 H5.H5Tget_member_value(tid, i, val); 1018 switch ((int)H5.H5Tget_size(tid)) { 1019 case 1: 1020 enumStr = Byte.toString((HDFNativeData.byteToByte(val[0]))[0]); 1021 break; 1022 case 2: 1023 enumStr = Short.toString((HDFNativeData.byteToShort(val))[0]); 1024 break; 1025 case 4: 1026 enumStr = Integer.toString((HDFNativeData.byteToInt(val))[0]); 1027 break; 1028 case 8: 1029 enumStr = Long.toString((HDFNativeData.byteToLong(val))[0]); 1030 break; 1031 default: 1032 enumStr = "-1"; 1033 break; 1034 } 1035 enumMembers.put(enumStr, name); 1036 } 1037 } 1038 catch (Exception ex) { 1039 log.debug("fromNative(): enum type failure: ", ex); 1040 } 1041 } 1042 else if (nativeClass == HDF5Constants.H5T_VLEN) { 1043 long tmptid = HDF5Constants.H5I_INVALID_HID; 1044 datatypeClass = CLASS_VLEN; 1045 isVLEN = true; 1046 try { 1047 log.trace("fromNative(): vlen type"); 1048 tmptid = H5.H5Tget_super(tid); 1049 baseType = new H5Datatype(this.fileFormat, tmptid, this); 1050 if (baseType == null) { 1051 log.debug("fromNative(): VLEN datatype has null base type"); 1052 throw new Exception("Datatype (VLEN) has no base datatype"); 1053 } 1054 1055 datatypeSign = baseType.getDatatypeSign(); 1056 } 1057 catch (Exception ex) { 1058 log.debug("fromNative(): vlen type failure: ", ex); 1059 } 1060 finally { 1061 close(tmptid); 1062 } 1063 } 1064 else if (nativeClass == HDF5Constants.H5T_BITFIELD) { 1065 datatypeClass = CLASS_BITFIELD; 1066 } 1067 else if (nativeClass == HDF5Constants.H5T_OPAQUE) { 1068 datatypeClass = CLASS_OPAQUE; 1069 1070 try { 1071 opaqueTag = H5.H5Tget_tag(tid); 1072 } 1073 catch (Exception ex) { 1074 log.debug("fromNative(): opaque type tag retrieval failed: ", ex); 1075 opaqueTag = null; 1076 } 1077 } 1078 else { 1079 log.debug("fromNative(): datatypeClass is unknown"); 1080 } 1081 1082 datatypeSize = (isVLEN && !isVariableStr) ? HDF5Constants.H5T_VL_T : tsize; 1083 } 1084 log.trace("fromNative(): datatypeClass={} baseType={} datatypeSize={}", datatypeClass, baseType, datatypeSize); 1085 } 1086 1087 /** 1088 * @param tid 1089 * the datatype identification disk. 1090 * 1091 * @return the memory datatype identifier if successful, and negative otherwise. 1092 */ 1093 public static long toNative(long tid) { 1094 // data type information 1095 log.trace("toNative(): tid={} start", tid); 1096 long nativeID = HDF5Constants.H5I_INVALID_HID; 1097 1098 try { 1099 nativeID = H5.H5Tget_native_type(tid); 1100 } 1101 catch (Exception ex) { 1102 log.debug("toNative(): H5Tget_native_type(tid {}) failure: ", tid, ex); 1103 } 1104 1105 try { 1106 if (H5.H5Tis_variable_str(tid)) 1107 H5.H5Tset_size(nativeID, HDF5Constants.H5T_VARIABLE); 1108 } 1109 catch (Exception ex) { 1110 log.debug("toNative(): var str type size failure: ", ex); 1111 } 1112 1113 return nativeID; 1114 } 1115 1116 /* 1117 * (non-Javadoc) 1118 * 1119 * @see hdf.object.Datatype#createNative() 1120 */ 1121 @SuppressWarnings("rawtypes") 1122 @Override 1123 public long createNative() { 1124 long tid = HDF5Constants.H5I_INVALID_HID; 1125 long tmptid = HDF5Constants.H5I_INVALID_HID; 1126 1127 String the_path = getFullName(); 1128 // isNamed == true should have non-null fileFormat 1129 if (isNamed()) { 1130 try { 1131 tid = H5.H5Topen(getFID(), the_path, HDF5Constants.H5P_DEFAULT); 1132 } 1133 catch (Exception ex) { 1134 log.debug("createNative(): name {} H5Topen failure: ", the_path, ex); 1135 } 1136 } 1137 else 1138 log.debug("createNative(): isNamed={} and named path={}", isNamed(), the_path); 1139 1140 if (tid >= 0) 1141 return tid; 1142 1143 log.trace("createNative(): datatypeClass={} datatypeSize={} baseType={}", datatypeClass, datatypeSize, baseType); 1144 1145 switch (datatypeClass) { 1146 case CLASS_ARRAY: 1147 try { 1148 if (baseType == null) { 1149 log.debug("createNative(): CLASS_ARRAY base type is NULL"); 1150 break; 1151 } 1152 1153 if ((tmptid = baseType.createNative()) < 0) { 1154 log.debug("createNative(): failed to create native datatype for ARRAY base datatype"); 1155 break; 1156 } 1157 1158 tid = H5.H5Tarray_create(tmptid, arrayDims.length, arrayDims); 1159 } 1160 catch (Exception ex) { 1161 log.debug("createNative(): native array datatype creation failed: ", ex); 1162 if (tid >= 0) close(tid); 1163 tid = HDF5Constants.H5I_INVALID_HID; 1164 } 1165 finally { 1166 close(tmptid); 1167 } 1168 1169 break; 1170 case CLASS_COMPOUND: 1171 try { 1172 tid = H5.H5Tcreate(CLASS_COMPOUND, datatypeSize); 1173 1174 for (int i = 0; i < compoundMemberTypes.size(); i++) { 1175 H5Datatype memberType = null; 1176 String memberName = null; 1177 long memberOffset = -1; 1178 1179 try { 1180 memberType = (H5Datatype) compoundMemberTypes.get(i); 1181 } 1182 catch (Exception ex) { 1183 log.debug("createNative(): get compound member[{}] type failure: ", i, ex); 1184 memberType = null; 1185 } 1186 1187 try { 1188 memberName = compoundMemberNames.get(i); 1189 } 1190 catch (Exception ex) { 1191 log.debug("createNative(): get compound member[{}] name failure: ", i, ex); 1192 memberName = null; 1193 } 1194 1195 try { 1196 memberOffset = compoundMemberOffsets.get(i); 1197 } 1198 catch (Exception ex) { 1199 log.debug("createNative(): get compound member[{}] offset failure: ", i, ex); 1200 memberOffset = -1; 1201 } 1202 1203 long memberID = HDF5Constants.H5I_INVALID_HID; 1204 try { 1205 memberID = memberType.createNative(); 1206 log.trace("createNative(): {} member[{}] with offset={} ID={}: ", memberName, i, 1207 memberOffset, memberID); 1208 1209 H5.H5Tinsert(tid, memberName, memberOffset, memberID); 1210 } 1211 catch (Exception ex) { 1212 log.debug("createNative(): compound type member[{}] insertion failure: ", i, ex); 1213 } 1214 finally { 1215 close(memberID); 1216 } 1217 } 1218 } 1219 catch (Exception ex) { 1220 log.debug("createNative(): native compound datatype creation failed: ", ex); 1221 if (tid >= 0) close(tid); 1222 tid = HDF5Constants.H5I_INVALID_HID; 1223 } 1224 break; 1225 case CLASS_INTEGER: 1226 log.trace("createNative(): CLASS_INT of size {}", datatypeSize); 1227 1228 try { 1229 switch ((int) datatypeSize) { 1230 case 1: 1231 log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT8"); 1232 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT8); 1233 break; 1234 case 2: 1235 log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT16"); 1236 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT16); 1237 break; 1238 case 4: 1239 log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT32"); 1240 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT32); 1241 break; 1242 case 8: 1243 log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT64"); 1244 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT64); 1245 break; 1246 default: 1247 if (datatypeSize == NATIVE) { 1248 log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT"); 1249 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT); 1250 } 1251 else { 1252 /* Custom sized integer */ 1253 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT8); 1254 H5.H5Tset_size(tid, datatypeSize); 1255 H5.H5Tset_precision(tid, 8 * datatypeSize); 1256 } 1257 break; 1258 } 1259 1260 if (datatypeOrder == Datatype.ORDER_BE) { 1261 log.trace("createNative(): CLASS_INT order is H5T_ORDER_BE"); 1262 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE); 1263 } 1264 else if (datatypeOrder == Datatype.ORDER_LE) { 1265 log.trace("createNative(): CLASS_INT order is H5T_ORDER_LE"); 1266 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE); 1267 } 1268 1269 if (datatypeSign == Datatype.SIGN_NONE) { 1270 log.trace("createNative(): CLASS_INT sign is H5T_SGN_NONE"); 1271 H5.H5Tset_sign(tid, HDF5Constants.H5T_SGN_NONE); 1272 } 1273 } 1274 catch (Exception ex) { 1275 log.debug("createNative(): native integer datatype creation failed: ", ex); 1276 if (tid >= 0) close(tid); 1277 tid = -1; 1278 } 1279 1280 break; 1281 case CLASS_ENUM: 1282 log.trace("createNative(): CLASS_ENUM"); 1283 try { 1284 if (baseType != null) { 1285 if ((tmptid = baseType.createNative()) < 0) { 1286 log.debug("createNative(): failed to create native type for ENUM base datatype"); 1287 break; 1288 } 1289 1290 tid = H5.H5Tenum_create(tmptid); 1291 } 1292 else { 1293 if (datatypeSize == NATIVE) 1294 datatypeSize = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_INT); 1295 1296 tid = H5.H5Tcreate(HDF5Constants.H5T_ENUM, datatypeSize); 1297 } 1298 1299 if (datatypeOrder == Datatype.ORDER_BE) { 1300 log.trace("createNative(): CLASS_ENUM order is H5T_ORDER_BE"); 1301 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE); 1302 } 1303 else if (datatypeOrder == Datatype.ORDER_LE) { 1304 log.trace("createNative(): CLASS_ENUM order is H5T_ORDER_LE"); 1305 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE); 1306 } 1307 1308 if (datatypeSign == Datatype.SIGN_NONE) { 1309 log.trace("createNative(): CLASS_ENUM sign is H5T_SGN_NONE"); 1310 H5.H5Tset_sign(tid, HDF5Constants.H5T_SGN_NONE); 1311 } 1312 } 1313 catch (Exception ex) { 1314 log.debug("createNative(): native enum datatype creation failed: ", ex); 1315 if (tid >= 0) close(tid); 1316 tid = HDF5Constants.H5I_INVALID_HID; 1317 } 1318 finally { 1319 close(tmptid); 1320 } 1321 1322 break; 1323 case CLASS_FLOAT: 1324 try { 1325 if (datatypeSize > 8) 1326 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_LDOUBLE); 1327 else 1328 tid = H5.H5Tcopy((datatypeSize == 8) ? HDF5Constants.H5T_NATIVE_DOUBLE : HDF5Constants.H5T_NATIVE_FLOAT); 1329 1330 if (datatypeOrder == Datatype.ORDER_BE) { 1331 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE); 1332 } 1333 else if (datatypeOrder == Datatype.ORDER_LE) { 1334 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE); 1335 } 1336 1337 if (nativeFPebias > 0) { 1338 H5.H5Tset_ebias(tid, nativeFPebias); 1339 } 1340 1341 if (nativeFPnorm >= 0) { 1342 H5.H5Tset_norm(tid, nativeFPnorm); 1343 } 1344 1345 if (nativeFPinpad >= 0) { 1346 H5.H5Tset_inpad(tid, nativeFPinpad); 1347 } 1348 1349 if ((nativeFPesize >= 0) && (nativeFPmsize >= 0)) { 1350 H5.H5Tset_fields(tid, nativeFPspos, nativeFPmpos, nativeFPesize, nativeFPmpos, nativeFPmsize); 1351 } 1352 } 1353 catch (Exception ex) { 1354 log.debug("createNative(): native floating-point datatype creation failed: ", ex); 1355 if (tid >= 0) close(tid); 1356 tid = HDF5Constants.H5I_INVALID_HID; 1357 } 1358 1359 break; 1360 case CLASS_CHAR: 1361 try { 1362 tid = H5.H5Tcopy((datatypeSign == Datatype.SIGN_NONE) ? HDF5Constants.H5T_NATIVE_UCHAR 1363 : HDF5Constants.H5T_NATIVE_CHAR); 1364 } 1365 catch (Exception ex) { 1366 log.debug("createNative(): native character datatype creation failed: ", ex); 1367 if (tid >= 0) close(tid); 1368 tid = HDF5Constants.H5I_INVALID_HID; 1369 } 1370 1371 break; 1372 case CLASS_STRING: 1373 try { 1374 tid = H5.H5Tcopy(HDF5Constants.H5T_C_S1); 1375 1376 H5.H5Tset_size(tid, (isVLEN || datatypeSize < 0) ? HDF5Constants.H5T_VARIABLE : datatypeSize); 1377 1378 log.trace("createNative(): isVlenStr={} nativeStrPad={} nativeStrCSET={}", isVLEN, nativeStrPad, 1379 nativeStrCSET); 1380 1381 H5.H5Tset_strpad(tid, (nativeStrPad >= 0) ? nativeStrPad : HDF5Constants.H5T_STR_NULLTERM); 1382 1383 if (nativeStrCSET >= 0) { 1384 H5.H5Tset_cset(tid, nativeStrCSET); 1385 } 1386 } 1387 catch (Exception ex) { 1388 log.debug("createNative(): native string datatype creation failed: ", ex); 1389 if (tid >= 0) close(tid); 1390 tid = HDF5Constants.H5I_INVALID_HID; 1391 } 1392 1393 break; 1394 case CLASS_REFERENCE: 1395 try { 1396 long objRefTypeSize = H5.H5Tget_size(HDF5Constants.H5T_STD_REF_OBJ); 1397 long dsetRefTypeSize = H5.H5Tget_size(HDF5Constants.H5T_STD_REF_DSETREG); 1398 // use datatypeSize as which type to copy 1399 log.debug("createNative(): datatypeSize:{} ", datatypeSize); 1400 if (datatypeSize > objRefTypeSize) { 1401 tid = H5.H5Tcopy(HDF5Constants.H5T_STD_REF_DSETREG); 1402 log.debug("createNative(): HDF5Constants.H5T_STD_REF_DSETREG"); 1403 } 1404 else { 1405 tid = H5.H5Tcopy(HDF5Constants.H5T_STD_REF_OBJ); 1406 log.debug("createNative(): HDF5Constants.H5T_STD_REF_OBJ"); 1407 } 1408 } 1409 catch (Exception ex) { 1410 log.debug("createNative(): native reference datatype creation failed: ", ex); 1411 if (tid >= 0) 1412 close(tid); 1413 tid = HDF5Constants.H5I_INVALID_HID; 1414 } 1415 1416 break; 1417 case CLASS_VLEN: 1418 try { 1419 if (baseType == null) { 1420 log.debug("createNative(): CLASS_VLEN base type is NULL"); 1421 break; 1422 } 1423 1424 if ((tmptid = baseType.createNative()) < 0) { 1425 log.debug("createNative(): failed to create native datatype for VLEN base datatype"); 1426 break; 1427 } 1428 1429 tid = H5.H5Tvlen_create(tmptid); 1430 } 1431 catch (Exception ex) { 1432 log.debug("createNative(): native variable-length datatype creation failed: ", ex); 1433 if (tid >= 0) close(tid); 1434 tid = HDF5Constants.H5I_INVALID_HID; 1435 } 1436 finally { 1437 close(tmptid); 1438 } 1439 1440 break; 1441 case CLASS_BITFIELD: 1442 log.trace("createNative(): CLASS_BITFIELD size is {}", datatypeSize); 1443 1444 try { 1445 switch ((int) datatypeSize) { 1446 case 1: 1447 log.trace("createNative(): CLASS_BITFIELD is H5T_NATIVE_B8"); 1448 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B8); 1449 break; 1450 case 2: 1451 log.trace("createNative(): CLASS_BITFIELD is H5T_NATIVE_B16"); 1452 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B16); 1453 break; 1454 case 4: 1455 log.trace("createNative(): CLASS_BITFIELD is H5T_NATIVE_B32"); 1456 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B32); 1457 break; 1458 case 8: 1459 log.trace("createNative(): CLASS_BITFIELD is H5T_NATIVE_B64"); 1460 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B64); 1461 break; 1462 default: 1463 if (datatypeSize == NATIVE) 1464 datatypeSize = 1; 1465 1466 /* Custom sized bitfield */ 1467 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B8); 1468 H5.H5Tset_size(tid, datatypeSize); 1469 H5.H5Tset_precision(tid, 8 * datatypeSize); 1470 1471 break; 1472 } 1473 1474 if (datatypeOrder == Datatype.ORDER_BE) { 1475 log.trace("createNative(): CLASS_BITFIELD order is H5T_ORDER_BE"); 1476 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE); 1477 } 1478 else if (datatypeOrder == Datatype.ORDER_LE) { 1479 log.trace("createNative(): CLASS_BITFIELD order is H5T_ORDER_LE"); 1480 H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE); 1481 } 1482 } 1483 catch (Exception ex) { 1484 log.debug("createNative(): native bitfield datatype creation failed: ", ex); 1485 if (tid >= 0) close(tid); 1486 tid = HDF5Constants.H5I_INVALID_HID; 1487 } 1488 1489 break; 1490 case CLASS_OPAQUE: 1491 log.trace("createNative(): CLASS_OPAQUE is {}-byte H5T_OPAQUE", datatypeSize); 1492 1493 try { 1494 if (datatypeSize == NATIVE) 1495 tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_OPAQUE); 1496 else 1497 tid = H5.H5Tcreate(HDF5Constants.H5T_OPAQUE, datatypeSize); 1498 1499 if (opaqueTag != null) { 1500 H5.H5Tset_tag(tid, opaqueTag); 1501 } 1502 } 1503 catch (Exception ex) { 1504 log.debug("createNative(): native opaque datatype creation failed: ", ex); 1505 if (tid >= 0) close(tid); 1506 tid = HDF5Constants.H5I_INVALID_HID; 1507 } 1508 1509 break; 1510 default: 1511 log.debug("createNative(): Unknown class"); 1512 break; 1513 } // (tclass) 1514 1515 // set up enum members 1516 if ((datatypeClass == CLASS_ENUM) && (enumMembers != null)) { 1517 log.trace("createNative(): set up enum members"); 1518 try { 1519 String memstr; 1520 String memname; 1521 byte[] memval = null; 1522 1523 Iterator entries = enumMembers.entrySet().iterator(); 1524 while (entries.hasNext()) { 1525 Entry thisEntry = (Entry) entries.next(); 1526 memstr = (String) thisEntry.getKey(); 1527 memname = (String) thisEntry.getValue(); 1528 1529 if (datatypeSize == 1) { 1530 log.trace("createNative(): CLASS_ENUM is H5T_NATIVE_INT8"); 1531 Byte tval = Byte.parseByte(memstr); 1532 memval = HDFNativeData.byteToByte(tval); 1533 } 1534 else if (datatypeSize == 2) { 1535 log.trace("createNative(): CLASS_ENUM is H5T_NATIVE_INT16"); 1536 Short tval = Short.parseShort(memstr); 1537 memval = HDFNativeData.shortToByte(tval); 1538 } 1539 else if (datatypeSize == 4) { 1540 log.trace("createNative(): CLASS_ENUM is H5T_NATIVE_INT32"); 1541 Integer tval = Integer.parseInt(memstr); 1542 memval = HDFNativeData.intToByte(tval); 1543 } 1544 else if (datatypeSize == 8) { 1545 log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT64"); 1546 Long tval = Long.parseLong(memstr); 1547 memval = HDFNativeData.longToByte(tval); 1548 } 1549 else { 1550 log.debug("createNative(): enum datatypeSize incorrect"); 1551 } 1552 log.trace("createNative(): H5Tenum_insert {} {}", memname, memval); 1553 H5.H5Tenum_insert(tid, memname, memval); 1554 } 1555 } 1556 catch (Exception ex) { 1557 log.debug("createNative(): set up enum members failure: ", ex); 1558 } 1559 } // (datatypeClass == CLASS_ENUM) 1560 1561 try { 1562 tmptid = tid; 1563 tid = H5.H5Tget_native_type(tmptid); 1564 } 1565 catch (HDF5Exception ex) { 1566 log.debug("createNative(): H5Tget_native_type({}) failure: ", tmptid, ex); 1567 } 1568 finally { 1569 close(tmptid); 1570 } 1571 1572 return tid; 1573 } 1574 1575 /** 1576 * Allocates a one-dimensional array of byte, short, int, long, float, double, 1577 * or String to store data in memory. 1578 * 1579 * For example, 1580 * 1581 * <pre> 1582 * long tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT32); 1583 * int[] data = (int[]) H5Datatype.allocateArray(datatype, 100); 1584 * </pre> 1585 * 1586 * returns a 32-bit integer array of size 100. 1587 * 1588 * @param dtype 1589 * the type. 1590 * @param numPoints 1591 * the total number of data points of the array. 1592 * 1593 * @return the array object if successful; otherwise, return null. 1594 * 1595 * @throws OutOfMemoryError 1596 * If there is a failure. 1597 */ 1598 public static final Object allocateArray(final H5Datatype dtype, int numPoints) throws OutOfMemoryError { 1599 log.trace("allocateArray(): start: numPoints={}", numPoints); 1600 1601 Object data = null; 1602 H5Datatype baseType = (H5Datatype) dtype.getDatatypeBase(); 1603 int typeClass = dtype.getDatatypeClass(); 1604 long typeSize = dtype.getDatatypeSize(); 1605 1606 if (numPoints < 0) { 1607 log.debug("allocateArray(): numPoints < 0"); 1608 return null; 1609 } 1610 1611 // Scalar members have dimensionality zero, i.e. size =0 1612 // what can we do about it, set the size to 1 1613 if (numPoints == 0) 1614 numPoints = 1; 1615 1616 log.trace("allocateArray(): tclass={} : tsize={}", typeClass, typeSize); 1617 1618 if (dtype.isVarStr() || dtype.isVLEN() || dtype.isRegRef()) { 1619 log.trace("allocateArray(): is_variable_str={} || isVL={} || is_reg_ref={}", dtype.isVarStr(), dtype.isVLEN(), dtype.isRegRef()); 1620 1621 data = new String[numPoints]; 1622 for (int i = 0; i < numPoints; i++) 1623 ((String[]) data)[i] = ""; 1624 } 1625 else if (typeClass == HDF5Constants.H5T_INTEGER) { 1626 log.trace("allocateArray(): class H5T_INTEGER"); 1627 if (typeSize == NATIVE) 1628 typeSize = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_INT); 1629 1630 switch ((int) typeSize) { 1631 case 1: 1632 data = new byte[numPoints]; 1633 break; 1634 case 2: 1635 data = new short[numPoints]; 1636 break; 1637 case 4: 1638 data = new int[numPoints]; 1639 break; 1640 case 8: 1641 data = new long[numPoints]; 1642 break; 1643 default: 1644 break; 1645 } 1646 } 1647 else if (typeClass == HDF5Constants.H5T_ENUM) { 1648 log.trace("allocateArray(): class H5T_ENUM"); 1649 1650 if (baseType != null) 1651 data = H5Datatype.allocateArray(baseType, numPoints); 1652 else { 1653 if (typeSize == NATIVE) 1654 typeSize = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_INT); 1655 data = new byte[(int) (numPoints * typeSize)]; 1656 } 1657 } 1658 else if (typeClass == HDF5Constants.H5T_COMPOUND) { 1659 log.trace("allocateArray(): class H5T_COMPOUND"); 1660 1661 data = new ArrayList<>(dtype.getCompoundMemberTypes().size()); 1662 } 1663 else if (typeClass == HDF5Constants.H5T_FLOAT) { 1664 log.trace("allocateArray(): class H5T_FLOAT"); 1665 if (typeSize == NATIVE) 1666 typeSize = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_FLOAT); 1667 1668 switch ((int) typeSize) { 1669 case 4: 1670 data = new float[numPoints]; 1671 break; 1672 case 8: 1673 data = new double[numPoints]; 1674 break; 1675 case 16: 1676 data = new byte[numPoints*16]; 1677 break; 1678 default: 1679 break; 1680 } 1681 } 1682 else if ((typeClass == HDF5Constants.H5T_STRING) || (typeClass == HDF5Constants.H5T_REFERENCE)) { 1683 log.trace("allocateArray(): class H5T_STRING || H5T_REFERENCE"); 1684 1685 data = new byte[(int) (numPoints * typeSize)]; 1686 } 1687 else if (typeClass == HDF5Constants.H5T_ARRAY) { 1688 log.trace("allocateArray(): class H5T_ARRAY"); 1689 1690 try { 1691 log.trace("allocateArray(): ArrayRank={}", dtype.getArrayDims().length); 1692 1693 // Use the base datatype to define the array 1694 long[] arrayDims = dtype.getArrayDims(); 1695 int asize = numPoints; 1696 for (int j = 0; j < arrayDims.length; j++) { 1697 log.trace("allocateArray(): Array dims[{}]={}", j, arrayDims[j]); 1698 1699 asize *= arrayDims[j]; 1700 } 1701 1702 if (baseType != null) 1703 data = H5Datatype.allocateArray(baseType, asize); 1704 } 1705 catch (Exception ex) { 1706 log.debug("allocateArray(): H5T_ARRAY class failure: ", ex); 1707 } 1708 } 1709 else if ((typeClass == HDF5Constants.H5T_OPAQUE) || (typeClass == HDF5Constants.H5T_BITFIELD)) { 1710 log.trace("allocateArray(): class H5T_OPAQUE || H5T_BITFIELD"); 1711 if (typeSize == NATIVE) 1712 typeSize = H5.H5Tget_size(typeClass); 1713 1714 data = new byte[(int) (numPoints * typeSize)]; 1715 } 1716 else { 1717 log.debug("allocateArray(): class ???? ({})", typeClass); 1718 1719 data = null; 1720 } 1721 1722 return data; 1723 } 1724 1725 /** 1726 * Returns the size (in bytes) of a given datatype identifier. 1727 * 1728 * It basically just calls H5Tget_size(tid). 1729 * 1730 * @param tid 1731 * The datatype identifier. 1732 * 1733 * @return The size of the datatype in bytes. 1734 * 1735 * @see hdf.hdf5lib.H5#H5Tget_size(long) 1736 */ 1737 public static final long getDatatypeSize(long tid) { 1738 // data type information 1739 long tsize = -1; 1740 1741 try { 1742 tsize = H5.H5Tget_size(tid); 1743 } 1744 catch (Exception ex) { 1745 tsize = -1; 1746 } 1747 1748 return tsize; 1749 } 1750 1751 /* 1752 * (non-Javadoc) 1753 * 1754 * @see hdf.object.Datatype#getDescription() 1755 */ 1756 @Override 1757 public String getDescription() { 1758 log.trace("getDescription(): start - isNamed={}", isNamed()); 1759 1760 if (datatypeDescription != null) 1761 return datatypeDescription; 1762 1763 StringBuilder description = new StringBuilder(); 1764 long tid = HDF5Constants.H5I_INVALID_HID; 1765 1766 switch (datatypeClass) { 1767 case CLASS_CHAR: 1768 log.trace("getDescription(): Char"); 1769 description.append("8-bit ").append(isUnsigned() ? "unsigned " : "").append("integer"); 1770 break; 1771 case CLASS_INTEGER: 1772 log.trace("getDescription(): Int"); 1773 if (datatypeSize == NATIVE) 1774 description.append("native ").append(isUnsigned() ? "unsigned " : "").append("integer"); 1775 else 1776 description.append(String.valueOf(datatypeSize * 8)).append("-bit ").append(isUnsigned() ? "unsigned " : "").append("integer"); 1777 break; 1778 case CLASS_FLOAT: 1779 log.trace("getDescription(): Float"); 1780 if (datatypeSize == NATIVE) 1781 description.append("native floating-point"); 1782 else 1783 description.append(String.valueOf(datatypeSize * 8)).append("-bit floating-point"); 1784 break; 1785 case CLASS_STRING: 1786 log.trace("getDescription(): String"); 1787 description.append("String, length = ").append(isVarStr() ? "variable" : datatypeSize); 1788 1789 try { 1790 tid = createNative(); 1791 if (tid >= 0) { 1792 String strPadType; 1793 String strCSETType; 1794 int strPad = H5.H5Tget_strpad(tid); 1795 int strCSET = H5.H5Tget_cset(tid); 1796 1797 if (strPad == HDF5Constants.H5T_STR_NULLTERM) 1798 strPadType = "H5T_STR_NULLTERM"; 1799 else if (strPad == HDF5Constants.H5T_STR_NULLPAD) 1800 strPadType = "H5T_STR_NULLPAD"; 1801 else if (strPad == HDF5Constants.H5T_STR_SPACEPAD) 1802 strPadType = "H5T_STR_SPACEPAD"; 1803 else 1804 strPadType = null; 1805 1806 if (strPadType != null) 1807 description.append(", padding = ").append(strPadType); 1808 1809 if (strCSET == HDF5Constants.H5T_CSET_ASCII) 1810 strCSETType = "H5T_CSET_ASCII"; 1811 else if (strCSET == HDF5Constants.H5T_CSET_UTF8) 1812 strCSETType = "H5T_CSET_UTF8"; 1813 else 1814 strCSETType = null; 1815 1816 if (strCSETType != null) 1817 description.append(", cset = ").append(strCSETType); 1818 } 1819 else { 1820 log.debug("createNative() failure"); 1821 } 1822 } 1823 catch (Exception ex) { 1824 log.debug("H5Tget_strpad failure: ", ex); 1825 } 1826 finally { 1827 close(tid); 1828 } 1829 break; 1830 case CLASS_BITFIELD: 1831 log.trace("getDescription(): Bit"); 1832 if (datatypeSize == NATIVE) 1833 description.append("native bitfield"); 1834 else 1835 description.append(String.valueOf(datatypeSize * 8)).append("-bit bitfield"); 1836 break; 1837 case CLASS_OPAQUE: 1838 log.trace("getDescription(): Opaque"); 1839 if (datatypeSize == NATIVE) 1840 description.append("native Opaque"); 1841 else 1842 description.append(String.valueOf(datatypeSize)).append("-byte Opaque"); 1843 1844 if (opaqueTag != null) { 1845 description.append(", tag = ").append(opaqueTag); 1846 } 1847 1848 break; 1849 case CLASS_COMPOUND: 1850 log.trace("getDescription(): Compound"); 1851 description.append("Compound"); 1852 1853 if ((compoundMemberTypes != null) && !compoundMemberTypes.isEmpty()) { 1854 Iterator<String> memberNames = null; 1855 Iterator<Datatype> memberTypes = compoundMemberTypes.iterator(); 1856 1857 if (compoundMemberNames != null) 1858 memberNames = compoundMemberNames.iterator(); 1859 1860 description.append(" {"); 1861 1862 while (memberTypes.hasNext()) { 1863 if (memberNames != null && memberNames.hasNext()) { 1864 description.append(memberNames.next()).append(" = "); 1865 } 1866 1867 description.append(memberTypes.next().getDescription()); 1868 1869 if (memberTypes.hasNext()) 1870 description.append(", "); 1871 } 1872 1873 description.append("}"); 1874 } 1875 1876 break; 1877 case CLASS_REFERENCE: 1878 log.trace("getDescription(): Ref"); 1879 description.append("Reference"); 1880 1881 try { 1882 boolean isRegionType = false; 1883 1884 tid = createNative(); 1885 if (tid >= 0) { 1886 isRegionType = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_DSETREG); 1887 1888 description.setLength(0); 1889 if (isRegionType) { 1890 description.append("Dataset region reference"); 1891 } 1892 else { 1893 description.append("Object reference"); 1894 } 1895 } 1896 } 1897 catch (Exception ex) { 1898 log.debug("H5.H5Tequal failure: ", ex); 1899 } 1900 finally { 1901 close(tid); 1902 } 1903 1904 break; 1905 case CLASS_ENUM: 1906 log.trace("getDescription(): Enum"); 1907 if (datatypeSize == NATIVE) 1908 description.append("native enum"); 1909 else 1910 description.append(String.valueOf(datatypeSize * 8)).append("-bit enum"); 1911 1912 String members = getEnumMembersAsString(); 1913 if (members != null) 1914 description.append(" (").append(members).append(")"); 1915 1916 break; 1917 case CLASS_VLEN: 1918 log.trace("getDescription(): Var Len"); 1919 description.append("Variable-length"); 1920 1921 if (baseType != null) 1922 description.append(" of ").append(baseType.getDescription()); 1923 1924 break; 1925 case CLASS_ARRAY: 1926 log.trace("getDescription(): Array"); 1927 description.append("Array"); 1928 1929 if (arrayDims != null) { 1930 description.append(" ["); 1931 for (int i = 0; i < arrayDims.length; i++) { 1932 description.append(arrayDims[i]); 1933 if (i < arrayDims.length - 1) 1934 description.append(" x "); 1935 } 1936 description.append("]"); 1937 } 1938 1939 if (baseType != null) 1940 description.append(" of ").append(baseType.getDescription()); 1941 1942 break; 1943 default: 1944 description.append("Unknown"); 1945 break; 1946 } 1947 if (isNamed()) 1948 description.append("->").append(getFullName()); 1949 1950 return description.toString(); 1951 } 1952 1953 /** 1954 * Checks if a datatype specified by the identifier is an unsigned integer. 1955 * 1956 * @param tid 1957 * the datatype ID to be checked. 1958 * 1959 * @return true is the datatype is an unsigned integer; otherwise returns false. 1960 */ 1961 public static final boolean isUnsigned(long tid) { 1962 boolean unsigned = false; 1963 1964 if (tid >= 0) { 1965 try { 1966 int tclass = H5.H5Tget_class(tid); 1967 log.trace("isUnsigned(): tclass = {}", tclass); 1968 if (tclass != HDF5Constants.H5T_FLOAT && tclass != HDF5Constants.H5T_STRING 1969 && tclass != HDF5Constants.H5T_REFERENCE && tclass != HDF5Constants.H5T_BITFIELD 1970 && tclass != HDF5Constants.H5T_OPAQUE && tclass != HDF5Constants.H5T_VLEN 1971 && tclass != HDF5Constants.H5T_COMPOUND && tclass != HDF5Constants.H5T_ARRAY) { 1972 int tsign = H5.H5Tget_sign(tid); 1973 if (tsign == HDF5Constants.H5T_SGN_NONE) 1974 unsigned = true; 1975 else 1976 log.trace("isUnsigned(): not unsigned"); 1977 } 1978 else { 1979 log.trace("isUnsigned(): tclass not integer type"); 1980 } 1981 } 1982 catch (Exception ex) { 1983 log.debug("isUnsigned(): Datatype {} failure", tid, ex); 1984 unsigned = false; 1985 } 1986 } 1987 else { 1988 log.trace("isUnsigned(): not a valid datatype"); 1989 } 1990 1991 return unsigned; 1992 } 1993 1994 /** 1995 * Removes all of the elements from metadata list. 1996 * The list should be empty after this call returns. 1997 */ 1998 @Override 1999 public void clear() { 2000 super.clear(); 2001 objMetadata.clear(); 2002 } 2003 2004 /** 2005 * Retrieves the object's metadata, such as attributes, from the file. 2006 * 2007 * Metadata, such as attributes, is stored in a List. 2008 * 2009 * @return the list of metadata objects. 2010 * 2011 * @throws HDF5Exception 2012 * if the metadata can not be retrieved 2013 */ 2014 @Override 2015 public List<Attribute> getMetadata() throws HDF5Exception { 2016 int gmIndexType = 0; 2017 int gmIndexOrder = 0; 2018 2019 try { 2020 gmIndexType = fileFormat.getIndexType(null); 2021 } 2022 catch (Exception ex) { 2023 log.debug("getMetadata(): getIndexType failed: ", ex); 2024 } 2025 try { 2026 gmIndexOrder = fileFormat.getIndexOrder(null); 2027 } 2028 catch (Exception ex) { 2029 log.debug("getMetadata(): getIndexOrder failed: ", ex); 2030 } 2031 return this.getMetadata(gmIndexType, gmIndexOrder); 2032 } 2033 2034 /** 2035 * Retrieves the object's metadata, such as attributes, from the file. 2036 * 2037 * Metadata, such as attributes, is stored in a List. 2038 * 2039 * @param attrPropList 2040 * the list of properties to get 2041 * 2042 * @return the list of metadata objects. 2043 * 2044 * @throws HDF5Exception 2045 * if the metadata can not be retrieved 2046 */ 2047 public List<Attribute> getMetadata(int... attrPropList) throws HDF5Exception { 2048 try { 2049 this.linkTargetObjName = H5File.getLinkTargetName(this); 2050 } 2051 catch (Exception ex) { 2052 log.debug("getMetadata(): getLinkTargetName failed: ", ex); 2053 } 2054 2055 List<Attribute> attrlist = null; 2056 try { 2057 attrlist = objMetadata.getMetadata(attrPropList); 2058 } 2059 catch (Exception ex) { 2060 log.debug("getMetadata(): getMetadata failed: ", ex); 2061 } 2062 return attrlist; 2063 } 2064 2065 /** 2066 * Writes a specific piece of metadata (such as an attribute) into the file. 2067 * 2068 * If an HDF(4&5) attribute exists in the file, this method updates its 2069 * value. If the attribute does not exist in the file, it creates the 2070 * attribute in the file and attaches it to the object. It will fail to 2071 * write a new attribute to the object where an attribute with the same name 2072 * already exists. To update the value of an existing attribute in the file, 2073 * one needs to get the instance of the attribute by getMetadata(), change 2074 * its values, then use writeMetadata() to write the value. 2075 * 2076 * @param info 2077 * the metadata to write. 2078 * 2079 * @throws Exception 2080 * if the metadata can not be written 2081 */ 2082 @Override 2083 public void writeMetadata(Object info) throws Exception { 2084 try { 2085 objMetadata.writeMetadata(info); 2086 } 2087 catch (Exception ex) { 2088 log.debug("writeMetadata(): Object not an Attribute"); 2089 } 2090 } 2091 2092 /** 2093 * Deletes an existing piece of metadata from this object. 2094 * 2095 * @param info 2096 * the metadata to delete. 2097 * 2098 * @throws HDF5Exception 2099 * if the metadata can not be removed 2100 */ 2101 @Override 2102 public void removeMetadata(Object info) throws HDF5Exception { 2103 try { 2104 objMetadata.removeMetadata(info); 2105 } 2106 catch (Exception ex) { 2107 log.debug("removeMetadata(): Object not an Attribute"); 2108 return; 2109 } 2110 2111 Attribute attr = (Attribute) info; 2112 log.trace("removeMetadata(): {}", attr.getAttributeName()); 2113 long tid = open(); 2114 if (tid >= 0) { 2115 try { 2116 H5.H5Adelete(tid, attr.getAttributeName()); 2117 } 2118 catch (Exception ex) { 2119 log.debug("removeMetadata(): ", ex); 2120 } 2121 finally { 2122 close(tid); 2123 } 2124 } 2125 else { 2126 log.debug("removeMetadata(): failed to open datatype"); 2127 } 2128 } 2129 2130 /** 2131 * Updates an existing piece of metadata attached to this object. 2132 * 2133 * @param info 2134 * the metadata to update. 2135 * 2136 * @throws HDF5Exception 2137 * if the metadata can not be updated 2138 */ 2139 @Override 2140 public void updateMetadata(Object info) throws HDF5Exception { 2141 try { 2142 objMetadata.updateMetadata(info); 2143 } 2144 catch (Exception ex) { 2145 log.debug("updateMetadata(): Object not an Attribute"); 2146 return; 2147 } 2148 } 2149 2150 /* 2151 * (non-Javadoc) 2152 * 2153 * @see hdf.object.HObject#setName(java.lang.String) 2154 */ 2155 @Override 2156 public void setName(String newName) throws Exception { 2157 if (newName == null) 2158 throw new IllegalArgumentException("The new name is NULL"); 2159 2160 H5File.renameObject(this, newName); 2161 super.setName(newName); 2162 } 2163 2164 @Override 2165 public void setFullname(String newPath, String newName) throws Exception { 2166 H5File.renameObject(this, newPath, newName); 2167 super.setFullname(newPath, newName); 2168 } 2169 2170 @Override 2171 public boolean isText() { 2172 return (datatypeClass == Datatype.CLASS_STRING); 2173 } 2174 2175 /** 2176 * Checks if this datatype is an object reference type. 2177 * 2178 * @return true if the datatype is an object reference; false otherwise 2179 */ 2180 public boolean isRefObj() { 2181 return isRefObj; 2182 } 2183 2184 /** 2185 * Checks if this datatype is a region reference type. 2186 * 2187 * @return true if the datatype is a region reference; false otherwise 2188 */ 2189 public boolean isRegRef() { 2190 return isRegRef; 2191 } 2192 2193 /** 2194 * Checks if this datatype is a reference type. 2195 * 2196 * @return true if the datatype is reference; false otherwise 2197 */ 2198 public boolean isReference() { 2199 log.trace("isReference():{}", datatypeClass); 2200 return (datatypeClass == Datatype.CLASS_REFERENCE); 2201 } 2202 2203 /* 2204 * (non-Javadoc) 2205 * 2206 * @see hdf.object.Datatype#getReferenceType() 2207 */ 2208 @Override 2209 public long getReferenceType() throws HDF5Exception { 2210 if (isRegRef) 2211 return HDF5Constants.H5T_STD_REF_DSETREG; 2212 if (isRefObj) 2213 return HDF5Constants.H5T_STD_REF_OBJ; 2214 return -1; 2215 } 2216 2217 /** 2218 * Checks if a reference datatype is all zero. 2219 * 2220 * @param refarr 2221 * the reference datatype data to be checked. 2222 * 2223 * @return true is the reference datatype data is all zero; otherwise returns false. 2224 */ 2225 public static final boolean zeroArrayCheck(final byte[] refarr) { 2226 for (byte b : refarr) { 2227 if (b != 0) 2228 return false; 2229 } 2230 return true; 2231 } 2232 2233 /** 2234 * Gets the string padding. 2235 * 2236 * @return the string padding value 2237 */ 2238 public int getNativeStrPad() { 2239 return nativeStrPad; 2240 } 2241 2242 /** 2243 * Extracts compound information into flat structure. 2244 * 2245 * For example, compound datatype "nest" has {nest1{a, b, c}, d, e} then extractCompoundInfo() will 2246 * put the names of nested compound fields into a flat list as 2247 * 2248 * <pre> 2249 * nest.nest1.a 2250 * nest.nest1.b 2251 * nest.nest1.c 2252 * nest.d 2253 * nest.e 2254 * </pre> 2255 * 2256 * @param dtype 2257 * the datatype to extract compound info from 2258 * @param name 2259 * the name of the compound datatype 2260 * @param names 2261 * the list to store the member names of the compound datatype 2262 * @param flatListTypes 2263 * the list to store the nested member names of the compound datatype 2264 */ 2265 public static void extractCompoundInfo(final H5Datatype dtype, String name, List<String> names, List<Datatype> flatListTypes) { 2266 log.trace("extractCompoundInfo(): start: name={}", name); 2267 2268 if (dtype.isArray()) { 2269 log.trace("extractCompoundInfo(): array type - extracting compound info from base datatype"); 2270 H5Datatype.extractCompoundInfo((H5Datatype) dtype.getDatatypeBase(), name, names, flatListTypes); 2271 } 2272 else if (dtype.isVLEN() && !dtype.isVarStr()) { 2273 log.trace("extractCompoundInfo(): variable-length type - extracting compound info from base datatype"); 2274 H5Datatype.extractCompoundInfo((H5Datatype) dtype.getDatatypeBase(), name, names, flatListTypes); 2275 } 2276 else if (dtype.isCompound()) { 2277 List<String> compoundMemberNames = dtype.getCompoundMemberNames(); 2278 List<Datatype> compoundMemberTypes = dtype.getCompoundMemberTypes(); 2279 Datatype mtype = null; 2280 String mname = null; 2281 2282 if (compoundMemberNames == null) { 2283 log.debug("extractCompoundInfo(): compoundMemberNames is null"); 2284 return; 2285 } 2286 2287 if (compoundMemberNames.isEmpty()) { 2288 log.debug("extractCompoundInfo(): compound datatype has no members"); 2289 return; 2290 } 2291 2292 log.trace("extractCompoundInfo(): nMembers={}", compoundMemberNames.size()); 2293 2294 for (int i = 0; i < compoundMemberNames.size(); i++) { 2295 log.trace("extractCompoundInfo(): member[{}]:", i); 2296 2297 mtype = compoundMemberTypes.get(i); 2298 2299 log.trace("extractCompoundInfo(): type={} with size={}", mtype.getDescription(), mtype.getDatatypeSize()); 2300 2301 if (names != null) { 2302 mname = name + compoundMemberNames.get(i); 2303 log.trace("extractCompoundInfo(): mname={}, name={}", mname, name); 2304 } 2305 2306 if (mtype.isCompound()) { 2307 H5Datatype.extractCompoundInfo((H5Datatype) mtype, mname + CompoundDS.SEPARATOR, names, flatListTypes); 2308 log.trace("extractCompoundInfo(): continue after recursive compound"); 2309 continue; 2310 } 2311 2312 if (names != null) { 2313 names.add(mname); 2314 } 2315 2316 flatListTypes.add(mtype); 2317 2318 /* 2319 * For ARRAY of COMPOUND and VLEN of COMPOUND types, we first add the top-level 2320 * array or vlen type to the list of datatypes, and then follow that with a 2321 * listing of the datatypes inside the nested compound. 2322 */ 2323 /* 2324 * TODO: Don't flatten variable-length types until true variable-length support 2325 * is implemented. 2326 */ 2327 if (mtype.isArray() /* || (mtype.isVLEN() && !mtype.isVarStr()) */) { 2328 H5Datatype.extractCompoundInfo((H5Datatype) mtype, mname + CompoundDS.SEPARATOR, names, flatListTypes); 2329 } 2330 } 2331 } 2332 } 2333 2334 /** 2335 * Creates a datatype of a compound with one field. 2336 * 2337 * This function is needed to read/write data field by field. 2338 * 2339 * @param memberName 2340 * The name of the datatype 2341 * 2342 * @return the identifier of the compound datatype. 2343 * 2344 * @throws HDF5Exception 2345 * If there is an error at the HDF5 library level. 2346 */ 2347 public long createCompoundFieldType(String memberName) throws HDF5Exception { 2348 log.trace("createCompoundFieldType(): start member_name={}", memberName); 2349 2350 long topTID = HDF5Constants.H5I_INVALID_HID; 2351 long tmpTID1 = HDF5Constants.H5I_INVALID_HID; 2352 2353 try { 2354 if (this.isArray()) { 2355 log.trace("createCompoundFieldType(): array datatype"); 2356 2357 if (baseType != null) { 2358 log.trace("createCompoundFieldType(): creating compound field type from base datatype"); 2359 tmpTID1 = ((H5Datatype) baseType).createCompoundFieldType(memberName); 2360 } 2361 2362 log.trace("createCompoundFieldType(): creating container array datatype"); 2363 topTID = H5.H5Tarray_create(tmpTID1, arrayDims.length, arrayDims); 2364 } 2365 else if (this.isVLEN()) { 2366 log.trace("createCompoundFieldType(): variable-length datatype"); 2367 2368 if (baseType != null) { 2369 log.trace("createCompoundFieldType(): creating compound field type from base datatype"); 2370 tmpTID1 = ((H5Datatype) baseType).createCompoundFieldType(memberName); 2371 } 2372 2373 log.trace("createCompoundFieldType(): creating container variable-length datatype"); 2374 topTID = H5.H5Tvlen_create(tmpTID1); 2375 } 2376 else if (this.isCompound()) { 2377 log.trace("createCompoundFieldType(): compound datatype"); 2378 2379 String insertedName = memberName; 2380 2381 int sep = memberName.indexOf(CompoundDS.SEPARATOR); 2382 if (sep >= 0) { 2383 /* 2384 * If a compound separator character is present in the supplied string, then 2385 * there is an additional level of compound nesting. We will create a compound 2386 * type to hold the nested compound type. 2387 */ 2388 insertedName = memberName.substring(0, sep); 2389 2390 log.trace("createCompoundFieldType(): member with name {} is nested inside compound", insertedName); 2391 } 2392 2393 /* 2394 * Retrieve the index of the compound member by its name. 2395 */ 2396 int memberIndex = this.compoundMemberNames.indexOf(insertedName); 2397 if (memberIndex >= 0) { 2398 H5Datatype memberType = (H5Datatype) this.compoundMemberTypes.get(memberIndex); 2399 2400 log.trace("createCompoundFieldType(): Member {} is type {} of size={} with baseType={}", insertedName, 2401 memberType.getDescription(), memberType.getDatatypeSize(), memberType.getDatatypeBase()); 2402 2403 if (sep >= 0) 2404 /* 2405 * Additional compound nesting; create the nested compound type. 2406 */ 2407 tmpTID1 = memberType.createCompoundFieldType(memberName.substring(sep + 1)); 2408 else 2409 tmpTID1 = memberType.createNative(); 2410 2411 log.trace("createCompoundFieldType(): creating container compound datatype"); 2412 topTID = H5.H5Tcreate(HDF5Constants.H5T_COMPOUND, datatypeSize); 2413 2414 log.trace("createCompoundFieldType(): inserting member {} into compound datatype", insertedName); 2415 H5.H5Tinsert(topTID, insertedName, 0, tmpTID1); 2416 2417 /* 2418 * WARNING!!! This step is crucial. Without it, the compound type created might be larger than 2419 * the size of the single datatype field we are inserting. Performing a read with a compound 2420 * datatype of an incorrect size will corrupt JVM memory and cause strange behavior and crashes. 2421 */ 2422 H5.H5Tpack(topTID); 2423 } 2424 else { 2425 log.debug("createCompoundFieldType(): member name {} not found in compound datatype's member name list", memberName); 2426 } 2427 } 2428 } 2429 catch (Exception ex) { 2430 log.debug("createCompoundFieldType(): creation of compound field type failed: ", ex); 2431 topTID = HDF5Constants.H5I_INVALID_HID; 2432 } 2433 finally { 2434 close(tmpTID1); 2435 } 2436 2437 return topTID; 2438 } 2439 2440 private boolean datatypeIsComplex(long tid) { 2441 long tclass = HDF5Constants.H5T_NO_CLASS; 2442 2443 try { 2444 tclass = H5.H5Tget_class(tid); 2445 log.trace("datatypeIsComplex():{}", tclass); 2446 } 2447 catch (Exception ex) { 2448 log.debug("datatypeIsComplex():", ex); 2449 } 2450 2451 boolean retVal = (tclass == HDF5Constants.H5T_COMPOUND); 2452 retVal |= (tclass == HDF5Constants.H5T_ENUM); 2453 retVal |= (tclass == HDF5Constants.H5T_VLEN); 2454 retVal |= (tclass == HDF5Constants.H5T_ARRAY); 2455 2456 return retVal; 2457 } 2458 2459 private boolean datatypeIsReference(long tid) { 2460 long tclass = HDF5Constants.H5T_NO_CLASS; 2461 2462 try { 2463 tclass = H5.H5Tget_class(tid); 2464 log.trace("datatypeIsReference():{}", tclass); 2465 } 2466 catch (Exception ex) { 2467 log.debug("datatypeIsReference():", ex); 2468 } 2469 2470 return (tclass == HDF5Constants.H5T_REFERENCE); 2471 } 2472 2473 private boolean datatypeIsAtomic(long tid) { 2474 boolean retVal = !(datatypeIsComplex(tid) | datatypeIsReference(tid) | isReference()); 2475 retVal |= isOpaque(); 2476 retVal |= isBitField(); 2477 2478 return retVal; 2479 } 2480 2481 private boolean datatypeClassIsComplex(long tclass) { 2482 boolean retVal = (tclass == HDF5Constants.H5T_COMPOUND); 2483 retVal |= (tclass == HDF5Constants.H5T_ENUM); 2484 retVal |= (tclass == HDF5Constants.H5T_VLEN); 2485 retVal |= (tclass == HDF5Constants.H5T_ARRAY); 2486 2487 return retVal; 2488 } 2489 2490 private boolean datatypeClassIsReference(long tclass) { 2491 return (tclass == HDF5Constants.H5T_REFERENCE); 2492 } 2493 2494 private boolean datatypeClassIsOpaque(long tclass) { 2495 return (tclass == Datatype.CLASS_OPAQUE); 2496 } 2497 2498 private boolean datatypeClassIsAtomic(long tclass) { 2499 boolean retVal = !(datatypeClassIsComplex(tclass) | datatypeClassIsReference(tclass)); 2500 retVal |= (tclass == Datatype.CLASS_OPAQUE); 2501 retVal |= (tclass == Datatype.CLASS_BITFIELD); 2502 2503 return retVal; 2504 } 2505}