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